home *** CD-ROM | disk | FTP | other *** search
/ Amiga Games Extra 1996 September / Amiga Games Extra CD-ROM 9-1996.iso / userbox / publicdomain / vim-4.2 / src / edit.c < prev    next >
C/C++ Source or Header  |  1996-06-09  |  86KB  |  3,579 lines

  1. /* vi:set ts=4 sw=4:
  2.  *
  3.  * VIM - Vi IMproved        by Bram Moolenaar
  4.  *
  5.  * Do ":help uganda"  in Vim to read copying and usage conditions.
  6.  * Do ":help credits" in Vim to see a list of people who contributed.
  7.  */
  8.  
  9. /*
  10.  * edit.c: functions for insert mode
  11.  */
  12.  
  13. #include "vim.h"
  14. #include "globals.h"
  15. #include "proto.h"
  16. #include "option.h"
  17. #include "ops.h"    /* for op_type */
  18.  
  19. #ifdef INSERT_EXPAND
  20. /*
  21.  * definitions used for CTRL-X submode
  22.  */
  23. #define CTRL_X_WANT_IDENT        0x100
  24.  
  25. #define CTRL_X_NOT_DEFINED_YET    (1)
  26. #define CTRL_X_SCROLL            (2)
  27. #define CTRL_X_WHOLE_LINE        (3)
  28. #define CTRL_X_FILES            (4)
  29. #define CTRL_X_TAGS                (5 + CTRL_X_WANT_IDENT)
  30. #define CTRL_X_PATH_PATTERNS    (6 + CTRL_X_WANT_IDENT)
  31. #define CTRL_X_PATH_DEFINES        (7 + CTRL_X_WANT_IDENT)
  32. #define CTRL_X_FINISHED            (8)
  33. #define CTRL_X_DICTIONARY        (9 + CTRL_X_WANT_IDENT)
  34.   
  35. struct Completion
  36. {
  37.     char_u                *str;
  38.     char_u                *fname;
  39.     int                    original;
  40.     struct Completion    *next;
  41.     struct Completion    *prev;
  42. };
  43.  
  44. struct Completion *first_match = NULL;
  45. struct Completion *curr_match = NULL;
  46.  
  47. static int add_completion __ARGS((char_u *str, int len, char_u *, int dir));
  48. static int make_cyclic __ARGS((void));
  49. static void complete_dictionaries __ARGS((char_u *, int));
  50. static void free_completions __ARGS((void));
  51. static int count_completions __ARGS((void));
  52. #endif /* INSERT_EXPAND */
  53.  
  54. #define BACKSPACE_CHAR                1
  55. #define BACKSPACE_WORD                2
  56. #define BACKSPACE_WORD_NOT_SPACE    3
  57. #define BACKSPACE_LINE                4
  58.  
  59. static void change_indent __ARGS((int type, int amount, int round));
  60. static void insert_special __ARGS((int, int));
  61. static void start_arrow __ARGS((FPOS *end_insert_pos));
  62. static void stop_arrow __ARGS((void));
  63. static void stop_insert __ARGS((FPOS *end_insert_pos));
  64. static int echeck_abbr __ARGS((int));
  65.  
  66. static FPOS     Insstart;        /* This is where the latest insert/append
  67.                                  * mode started. */
  68. static colnr_t    Insstart_textlen;    /* length of line when insert started */
  69. static colnr_t    Insstart_blank_vcol;    /* vcol for first inserted blank */
  70.  
  71. static char_u    *last_insert = NULL;
  72.                             /* the text of the previous insert */
  73. static int        last_insert_skip;
  74.                             /* number of chars in front of previous insert */
  75. static int        new_insert_skip;
  76.                             /* number of chars in front of the current insert */
  77. #ifdef INSERT_EXPAND
  78. static char_u    *original_text = NULL;
  79.                             /* Original text typed before completion */
  80. #endif
  81.  
  82. #ifdef CINDENT
  83. static int        can_cindent;    /* may do cindenting on this line */
  84. #endif
  85.  
  86. /*
  87.  * edit() returns TRUE if it returns because of a CTRL-O command
  88.  */
  89.     int
  90. edit(initstr, startln, count)
  91.     int            initstr;
  92.     int         startln;        /* if set, insert at start of line */
  93.     long         count;
  94. {
  95.     int             c;
  96.     int             cc;
  97.     char_u        *ptr;
  98.     linenr_t     lnum;
  99.     int          temp = 0;
  100.     int             mode;
  101.     int             lastc = 0;
  102.     colnr_t         mincol;
  103.     static linenr_t o_lnum = 0;
  104.     static int     o_eol = FALSE;
  105.     int             need_redraw = FALSE;
  106.     int             i;
  107.     int             did_backspace = TRUE;        /* previous char was backspace */
  108. #ifdef RIGHTLEFT
  109.     int            revins;                        /* reverse insert mode */
  110.     int            revinschars = 0;            /* how much to skip after edit */
  111.     int            revinslegal = 0;            /* was the last char 'legal'? */
  112.     int            revinsscol = -1;            /* start column of revins session */
  113. #endif
  114. #ifdef INSERT_EXPAND
  115.     FPOS         first_match_pos;
  116.     FPOS         last_match_pos;
  117.     FPOS        *complete_pos;
  118.     char_u        *complete_pat = NULL;
  119.     char_u        *tmp_ptr;
  120.     char_u        *mesg = NULL;                /* Message about completion */
  121.     char_u        *quick_m;                    /* Message without sleep */
  122.     int             started_completion = FALSE;
  123.     colnr_t         complete_col = 0;            /* init for gcc */
  124.     int             complete_direction;
  125.     int             done_dir = 0;                /* Found all matches in this
  126.                                              * direction */
  127.     int             num_matches;
  128.     char_u        **matches;
  129.     regexp        *prog;
  130.     int             save_sm = -1;                /* init for gcc */
  131.     int             save_p_scs;
  132. #endif
  133. #ifdef CINDENT
  134.     int             line_is_white = FALSE;        /* line is empty before insert */
  135. #endif
  136.     FPOS         tpos;
  137.  
  138.     /* sleep before redrawing, needed for "CTRL-O :" that results in an
  139.      * error message */
  140.     if (msg_scroll || emsg_on_display)    
  141.     {
  142.         mch_delay(1000L, TRUE);
  143.         msg_scroll = FALSE;
  144.         emsg_on_display = FALSE;
  145.     }
  146. #ifdef SLEEP_IN_EMSG
  147.     if (need_sleep)    
  148.     {
  149.         mch_delay(1000L, TRUE);
  150.         need_sleep = FALSE;
  151.     }
  152. #endif
  153.  
  154. #ifdef USE_MOUSE
  155.     /*
  156.      * When doing a paste with the middle mouse button, Insstart is set to
  157.      * where the paste started.
  158.      */
  159.     if (where_paste_started.lnum != 0)
  160.         Insstart = where_paste_started;
  161.     else
  162. #endif
  163.     {
  164.         Insstart = curwin->w_cursor;
  165.         if (startln)
  166.             Insstart.col = 0;
  167.     }
  168.     Insstart_textlen = linetabsize(ml_get_curline());
  169.     Insstart_blank_vcol = MAXCOL;
  170.  
  171.     if (initstr != NUL && !restart_edit)
  172.     {
  173.         ResetRedobuff();
  174.         AppendNumberToRedobuff(count);
  175.         AppendCharToRedobuff(initstr);
  176.         if (initstr == 'g')                    /* "gI" command */
  177.             AppendCharToRedobuff('I');
  178.     }
  179.  
  180.     if (initstr == 'R')
  181.         State = REPLACE;
  182.     else
  183.         State = INSERT;
  184.  
  185. #ifdef USE_MOUSE
  186.     setmouse();
  187. #endif
  188.     clear_showcmd();
  189. #ifdef RIGHTLEFT
  190.     revins = (State == INSERT && p_ri);    /* there is no reverse replace mode */
  191.     if (revins)
  192.         undisplay_dollar();
  193. #endif
  194.  
  195.     /*
  196.      * When CTRL-O . is used to repeat an insert, we get here with
  197.      * restart_edit non-zero, but something in the stuff buffer
  198.      */
  199.     if (restart_edit && stuff_empty())
  200.     {
  201. #ifdef USE_MOUSE
  202.         /*
  203.          * After a paste we consider text typed to be part of the insert for
  204.          * the pasted text. You can backspace over the paste text too.
  205.          */
  206.         if (where_paste_started.lnum)
  207.             arrow_used = FALSE;
  208.         else
  209. #endif
  210.             arrow_used = TRUE;
  211.         restart_edit = 0;
  212.         /*
  213.          * If the cursor was after the end-of-line before the CTRL-O
  214.          * and it is now at the end-of-line, put it after the end-of-line
  215.          * (this is not correct in very rare cases).
  216.          * Also do this if curswant is greater than the current virtual column.
  217.          * Eg after "^O$" or "^O80|".
  218.          */
  219.         if (((o_eol && curwin->w_cursor.lnum == o_lnum) ||
  220.                                 curwin->w_curswant > curwin->w_virtcol) &&
  221.                 *(ptr = ml_get_curline() + curwin->w_cursor.col)
  222.                                                                     != NUL &&
  223.                 *(ptr + 1) == NUL)
  224.             ++curwin->w_cursor.col;
  225.     }
  226.     else
  227.     {
  228.         arrow_used = FALSE;
  229.         o_eol = FALSE;
  230.     }
  231. #ifdef USE_MOUSE
  232.     where_paste_started.lnum = 0;
  233. #endif
  234. #ifdef CINDENT
  235.     can_cindent = TRUE;
  236. #endif
  237.  
  238.     if (p_smd)
  239.         showmode();
  240.  
  241.     if (!p_im)
  242.         change_warning();            /* give a warning if readonly */
  243.  
  244. #ifdef DIGRAPHS
  245.     do_digraph(-1);                    /* clear digraphs */
  246. #endif
  247.  
  248. /*
  249.  * Get the current length of the redo buffer, those characters have to be
  250.  * skipped if we want to get to the inserted characters.
  251.  */
  252.     ptr = get_inserted();
  253.     new_insert_skip = STRLEN(ptr);
  254.     vim_free(ptr);
  255.  
  256.     old_indent = 0;
  257.  
  258.     for (;;)
  259.     {
  260. #ifdef RIGHTLEFT
  261.         if (!revinslegal)
  262.             revinsscol = -1;        /* reset on illegal motions */
  263.         else
  264.             revinslegal = 0;
  265. #endif
  266.         if (arrow_used)        /* don't repeat insert when arrow key used */
  267.             count = 0;
  268.  
  269.             /* set curwin->w_curswant for next K_DOWN or K_UP */
  270.         if (!arrow_used)
  271.             curwin->w_set_curswant = TRUE;
  272.  
  273.             /* Figure out where the cursor is based on curwin->w_cursor. */
  274.         mincol = curwin->w_col;
  275.         i = curwin->w_row;
  276.         cursupdate();
  277.  
  278.         /*
  279.          * When emsg() was called msg_scroll will have been set.
  280.          */
  281.         msg_scroll = FALSE;
  282.  
  283.         /*
  284.          * If we inserted a character at the last position of the last line in
  285.          * the window, scroll the window one line up. This avoids an extra
  286.          * redraw.
  287.          * This is detected when the cursor column is smaller after inserting
  288.          * something.
  289.          */
  290.         if (curwin->w_p_wrap && !did_backspace &&
  291.                           (int)curwin->w_col < (int)mincol - curbuf->b_p_ts &&
  292.                                i == curwin->w_winpos + curwin->w_height - 1 &&
  293.                                    curwin->w_cursor.lnum != curwin->w_topline)
  294.         {
  295.             ++curwin->w_topline;
  296.             updateScreen(VALID_TO_CURSCHAR);
  297.             cursupdate();
  298.             need_redraw = FALSE;
  299.         }
  300.         did_backspace = FALSE;
  301.  
  302.         /*
  303.          * redraw is postponed until after cursupdate() to make 'dollar'
  304.          * option work correctly.
  305.          */
  306.         if (need_redraw)
  307.         {
  308.             updateline();
  309.             need_redraw = FALSE;
  310.         }
  311.  
  312.         showruler(0);
  313.         setcursor();
  314.         emsg_on_display = FALSE;        /* may remove error message now */
  315.  
  316.         c = vgetc();
  317.         if (c == Ctrl('C'))
  318.             got_int = FALSE;
  319.  
  320. #ifdef RIGHTLEFT
  321.         if (p_hkmap && KeyTyped)
  322.             c = hkmap(c);                /* Hebrew mode mapping */
  323. #endif
  324.  
  325. #ifdef INSERT_EXPAND
  326.         if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET)
  327.         {
  328.             /* We have just entered ctrl-x mode and aren't quite sure which
  329.              * ctrl-x mode it will be yet.  Now we decide -- webb
  330.              */
  331.             switch (c)
  332.             {
  333.                 case Ctrl('E'):
  334.                 case Ctrl('Y'):
  335.                     ctrl_x_mode = CTRL_X_SCROLL;
  336.                     if (State == INSERT)
  337.                         edit_submode = (char_u *)" (insert) Scroll (^E/^Y)";
  338.                     else
  339.                         edit_submode = (char_u *)" (replace) Scroll (^E/^Y)";
  340.                     break;
  341.                 case Ctrl('L'):
  342.                     ctrl_x_mode = CTRL_X_WHOLE_LINE;
  343.                     edit_submode = (char_u *)" Whole line completion (^L/^N/^P)";
  344.                     break;
  345.                 case Ctrl('F'):
  346.                     ctrl_x_mode = CTRL_X_FILES;
  347.                     edit_submode = (char_u *)" File name completion (^F/^N/^P)";
  348.                     break;
  349.                 case Ctrl('K'):
  350.                     ctrl_x_mode = CTRL_X_DICTIONARY;
  351.                     edit_submode = (char_u *)" Dictionary completion (^K/^N/^P)";
  352.                     break;
  353.                 case Ctrl(']'):
  354.                     ctrl_x_mode = CTRL_X_TAGS;
  355.                     edit_submode = (char_u *)" Tag completion (^]/^N/^P)";
  356.                     break;
  357.                 case Ctrl('I'):
  358.                     ctrl_x_mode = CTRL_X_PATH_PATTERNS;
  359.                     edit_submode = (char_u *)" Path pattern completion (^N/^P)";
  360.                     break;
  361.                 case Ctrl('D'):
  362.                     ctrl_x_mode = CTRL_X_PATH_DEFINES;
  363.                     edit_submode = (char_u *)" Definition completion (^D/^N/^P)";
  364.                     break;
  365.                 default:
  366.                     ctrl_x_mode = 0;
  367.                     break;
  368.             }
  369.             showmode();
  370.         }
  371.         else if (ctrl_x_mode)
  372.         {
  373.             /* We we're already in ctrl-x mode, do we stay in it? */
  374.             if (!is_ctrl_x_key(c))
  375.             {
  376.                 if (ctrl_x_mode == CTRL_X_SCROLL)
  377.                     ctrl_x_mode = 0;
  378.                 else
  379.                     ctrl_x_mode = CTRL_X_FINISHED;
  380.                 edit_submode = NULL;
  381.             }
  382.             showmode();
  383.         }
  384.         if (started_completion || ctrl_x_mode == CTRL_X_FINISHED)
  385.         {
  386.             /* Show error message from attempted keyword completion (probably
  387.              * 'Pattern not found') until another key is hit, then go back to
  388.              * showing what mode we are in.
  389.              */
  390.             showmode();
  391.             if ((ctrl_x_mode == 0 && c != Ctrl('N') && c != Ctrl('P')) ||
  392.                                                 ctrl_x_mode == CTRL_X_FINISHED)
  393.             {
  394.                 /* Get here when we have finished typing a sequence of ^N and
  395.                  * ^P or other completion characters in CTRL-X mode. Free up
  396.                  * memory that was used, and make sure we can redo the insert
  397.                  * -- webb.
  398.                  */
  399.                 if (curr_match != NULL)
  400.                 {
  401.                     /*
  402.                      * If any of the original typed text has been changed,
  403.                      * eg when ignorecase is set, we must add back-spaces to
  404.                      * the redo buffer.  We add as few as necessary to delete
  405.                      * just the part of the original text that has changed
  406.                      * -- webb
  407.                      */
  408.                     ptr = curr_match->str;
  409.                     tmp_ptr = original_text;
  410.                     while (*tmp_ptr && *tmp_ptr == *ptr)
  411.                     {
  412.                         ++tmp_ptr;
  413.                         ++ptr;
  414.                     }
  415.                     for (temp = 0; tmp_ptr[temp]; ++temp)
  416.                         AppendCharToRedobuff(K_BS);
  417.                     if (*ptr)
  418.                         AppendToRedobuff(ptr);
  419.                 }
  420.                 /* Break line if it's too long */
  421.                 lnum = curwin->w_cursor.lnum;
  422.                 insertchar(NUL, FALSE, -1);
  423.                 if (lnum != curwin->w_cursor.lnum)
  424.                     updateScreen(CURSUPD);
  425.                 else
  426.                     need_redraw = TRUE;
  427.  
  428.                 vim_free(complete_pat);
  429.                 complete_pat = NULL;
  430.                 vim_free(original_text);
  431.                 original_text = NULL;
  432.                 free_completions();
  433.                 started_completion = FALSE;
  434.                 ctrl_x_mode = 0;
  435.                 p_sm = save_sm;
  436.                 if (edit_submode != NULL)
  437.                 {
  438.                     edit_submode = NULL;
  439.                     showmode();
  440.                 }
  441.             }
  442.         }
  443. #endif /* INSERT_EXPAND */
  444.  
  445.         if (c != Ctrl('D'))            /* remember to detect ^^D and 0^D */
  446.             lastc = c;
  447.  
  448. #ifdef DIGRAPHS
  449.         c = do_digraph(c);
  450. #endif /* DIGRAPHS */
  451.  
  452.         if (c == Ctrl('V') || c == Ctrl('Q'))
  453.         {
  454.             if (NextScreen != NULL)
  455.                 screen_outchar('^', curwin->w_winpos + curwin->w_row,
  456. #ifdef RIGHTLEFT
  457.                     curwin->w_p_rl ? (int)Columns - 1 - curwin->w_col :
  458. #endif
  459.                                                                curwin->w_col);
  460.             AppendToRedobuff((char_u *)"\026");    /* CTRL-V */
  461.             cursupdate();
  462.  
  463.             if (!add_to_showcmd(c, FALSE))
  464.                 setcursor();
  465.  
  466.             c = get_literal();
  467.             clear_showcmd();
  468.             insert_special(c, TRUE);
  469.             need_redraw = TRUE;
  470. #ifdef RIGHTLEFT
  471.             revinschars++;
  472.             revinslegal++;
  473. #endif
  474.             continue;
  475.         }
  476.  
  477. #ifdef CINDENT
  478.         if (curbuf->b_p_cin
  479. # ifdef INSERT_EXPAND
  480.                             && !ctrl_x_mode
  481. # endif
  482.                                                )
  483.         {
  484.             line_is_white = inindent(0);
  485.  
  486.             /* 
  487.              * A key name preceded by a bang means that this
  488.              * key wasn't destined to be inserted.  Skip ahead
  489.              * to the re-indenting if we find one.
  490.              */
  491.             if (in_cinkeys(c, '!', line_is_white))
  492.                 goto force_cindent;
  493.  
  494.             /* 
  495.              * A key name preceded by a star means that indenting
  496.              * has to be done before inserting the key.
  497.              */
  498.             if (can_cindent && in_cinkeys(c, '*', line_is_white))
  499.             {
  500.                 stop_arrow();
  501.  
  502.                 /* re-indent the current line */
  503.                 fixthisline(get_c_indent);
  504.  
  505.                 /* draw the changes on the screen later */
  506.                 need_redraw = TRUE;
  507.             }
  508.         }
  509. #endif /* CINDENT */
  510.  
  511. #ifdef RIGHTLEFT
  512.         if (curwin->w_p_rl)
  513.             switch (c)
  514.             {
  515.                 case K_LEFT:    c = K_RIGHT; break;
  516.                 case K_S_LEFT:    c = K_S_RIGHT; break;
  517.                 case K_RIGHT:    c = K_LEFT; break;
  518.                 case K_S_RIGHT: c = K_S_LEFT; break;
  519.             }
  520. #endif
  521.  
  522.         switch (c)        /* handle character in insert mode */
  523.         {
  524.               case K_INS:            /* toggle insert/replace mode */
  525.                 if (State == REPLACE)
  526.                     State = INSERT;
  527.                 else
  528.                     State = REPLACE;
  529.                 AppendCharToRedobuff(K_INS);
  530.                 showmode();
  531.                 break;
  532.  
  533. #ifdef INSERT_EXPAND
  534.               case Ctrl('X'):        /* Enter ctrl-x mode */
  535.                 /* We're not sure which ctrl-x mode it will be yet */
  536.                 ctrl_x_mode = CTRL_X_NOT_DEFINED_YET;
  537.                 MSG("^X mode (^E/^Y/^L/^]/^F/^I/^K/^D)");
  538.                 break;
  539. #endif /* INSERT_EXPAND */
  540.  
  541.               case Ctrl('O'):        /* execute one command */
  542.                 if (echeck_abbr(Ctrl('O') + ABBR_OFF))
  543.                     break;
  544.                   count = 0;
  545.                 if (State == INSERT)
  546.                     restart_edit = 'I';
  547.                 else
  548.                     restart_edit = 'R';
  549.                 o_lnum = curwin->w_cursor.lnum;
  550.                 o_eol = (gchar_cursor() == NUL);
  551.                 goto doESCkey;
  552.  
  553.               /* Hitting the help key in insert mode is like <ESC> <Help> */
  554.               case K_HELP:
  555.               case K_F1:
  556.                   stuffcharReadbuff(K_HELP);
  557.                 /*FALLTHROUGH*/
  558.  
  559.               case ESC:             /* an escape ends input mode */
  560.                 if (echeck_abbr(ESC + ABBR_OFF))
  561.                     break;
  562.                 /*FALLTHROUGH*/
  563.  
  564.               case Ctrl('C'):
  565. doESCkey:
  566.                 temp = curwin->w_cursor.col;
  567.                 if (!arrow_used)
  568.                 {
  569.                     AppendToRedobuff(ESC_STR);
  570.  
  571.                     if (--count > 0)        /* repeat what was typed */
  572.                     {
  573.                         (void)start_redo_ins();
  574.                         continue;
  575.                     }
  576.                     stop_insert(&curwin->w_cursor);
  577.                     if (dollar_vcol)
  578.                     {
  579.                         dollar_vcol = 0;
  580.                         /* may have to redraw status line if this was the
  581.                          * first change, show "[+]" */
  582.                         if (curwin->w_redr_status == TRUE)
  583.                             must_redraw = NOT_VALID;
  584.                         else
  585.                             need_redraw = TRUE;
  586.                     }
  587.                 }
  588.                 if (need_redraw)
  589.                     updateline();
  590.  
  591.                 /* When an autoindent was removed, curswant stays after the
  592.                  * indent */
  593.                 if (!restart_edit && (colnr_t)temp == curwin->w_cursor.col)
  594.                     curwin->w_set_curswant = TRUE;
  595.  
  596.                 /*
  597.                  * The cursor should end up on the last inserted character.
  598.                  */
  599.                 if (curwin->w_cursor.col != 0 &&
  600.                           (!restart_edit || gchar_cursor() == NUL)
  601. #ifdef RIGHTLEFT
  602.                                       && !revins
  603. #endif
  604.                                                   )
  605.                     --curwin->w_cursor.col;
  606.                 if (State == REPLACE)
  607.                     replace_flush();    /* free replace stack */
  608.                 State = NORMAL;
  609. #ifdef USE_MOUSE
  610.                 setmouse();
  611. #endif
  612.                     /* inchar() may have deleted the "INSERT" message */
  613.                     /* for CTRL-O we display -- INSERT COMMAND -- */
  614.                 if (Recording || restart_edit)
  615.                     showmode();
  616.                 else if (p_smd)
  617.                     MSG("");
  618.                 old_indent = 0;
  619.                 return (c == Ctrl('O'));
  620.  
  621.                   /*
  622.                  * Insert the previously inserted text.
  623.                  * For ^@ the trailing ESC will end the insert, unless there
  624.                  * is an error.
  625.                  */
  626.               case K_ZERO:
  627.               case NUL:
  628.               case Ctrl('A'):
  629.                 if (stuff_inserted(NUL, 1L, (c == Ctrl('A'))) == FAIL &&
  630.                                                                c != Ctrl('A'))
  631.                     goto doESCkey;            /* quit insert mode */
  632.                 break;
  633.  
  634.                   /*
  635.                  * insert the contents of a register
  636.                  */
  637.               case Ctrl('R'):
  638.                 if (NextScreen != NULL)
  639.                     screen_outchar('"', curwin->w_winpos + curwin->w_row,
  640. #ifdef RIGHTLEFT
  641.                         curwin->w_p_rl ? (int)Columns - 1 - curwin->w_col :
  642. #endif
  643.                                                             curwin->w_col);
  644.                 if (!add_to_showcmd(c, FALSE))
  645.                     setcursor();
  646.                     /* don't map the register name. This also prevents the
  647.                      * mode message to be deleted when ESC is hit */
  648.                 ++no_mapping;
  649. #ifdef HAVE_LANGMAP
  650.                 cc = vgetc();
  651.                 LANGMAP_ADJUST(cc, TRUE);
  652.                   if (insertbuf(cc) == FAIL)
  653. #else
  654.                   if (insertbuf(vgetc()) == FAIL)
  655. #endif
  656.                 {
  657.                     beep_flush();
  658.                     need_redraw = TRUE;        /* remove the '"' */
  659.                 }
  660.                 --no_mapping;
  661.                 clear_showcmd();
  662.                 break;
  663.  
  664. #ifdef RIGHTLEFT
  665.               case Ctrl('B'):            /* toggle reverse insert mode */
  666.                   p_ri = !p_ri;
  667.                 revins = (State == INSERT && p_ri);
  668.                 if (revins)
  669.                     undisplay_dollar();
  670.                 showmode();
  671.                 break;
  672.  
  673.               case Ctrl('_'):        /* toggle language: khmap and revins */
  674.                                     /* Move to end of reverse inserted text */
  675.                 if (revins && revinschars && revinsscol >= 0)
  676.                     while (gchar_cursor() != NUL && revinschars--)
  677.                         ++curwin->w_cursor.col;
  678.                 p_ri = !p_ri;
  679.                 revins = (State == INSERT && p_ri);
  680.                 if (revins)
  681.                 {
  682.                     revinsscol = curwin->w_cursor.col;
  683.                     revinslegal++;
  684.                     revinschars = 0;
  685.                     undisplay_dollar();
  686.                 }
  687.                 else
  688.                     revinsscol = -1;
  689.                 p_hkmap = curwin->w_p_rl ^ p_ri;    /* be consistent! */
  690.                 showmode();
  691.                 break;
  692. #endif
  693.  
  694.                 /*
  695.                  * If the cursor is on an indent, ^T/^D insert/delete one
  696.                  * shiftwidth.  Otherwise ^T/^D behave like a "<<" or ">>".
  697.                  * Always round the indent to 'shiftwith', this is compatible
  698.                  * with vi.  But vi only supports ^T and ^D after an
  699.                  * autoindent, we support it everywhere.
  700.                  */
  701.               case Ctrl('D'):         /* make indent one shiftwidth smaller */
  702. #ifdef INSERT_EXPAND
  703.                 if (ctrl_x_mode == CTRL_X_PATH_DEFINES)
  704.                     goto docomplete;
  705. #endif /* INSERT_EXPAND */
  706.                 /* FALLTHROUGH */
  707.               case Ctrl('T'):        /* make indent one shiftwidth greater */
  708.                 stop_arrow();
  709.                 AppendCharToRedobuff(c);
  710.  
  711.                 /*
  712.                  * 0^D and ^^D: remove all indent.
  713.                  */
  714.                 if ((lastc == '0' || lastc == '^') && curwin->w_cursor.col)
  715.                 {
  716.                     --curwin->w_cursor.col;
  717.                     (void)delchar(FALSE);            /* delete the '^' or '0' */
  718.                     if (lastc == '^')
  719.                         old_indent = get_indent();    /* remember curr. indent */
  720.                     change_indent(INDENT_SET, 0, TRUE);
  721.                 }
  722.                 else
  723.                     change_indent(c == Ctrl('D') ? INDENT_DEC : INDENT_INC,
  724.                                                                      0, TRUE);
  725.  
  726.                 did_ai = FALSE;
  727.                 did_si = FALSE;
  728.                 can_si = FALSE;
  729.                 can_si_back = FALSE;
  730. #ifdef CINDENT
  731.                 can_cindent = FALSE;        /* no cindenting after ^D or ^T */
  732. #endif
  733.                   goto redraw;
  734.  
  735.               case K_DEL:
  736.                 stop_arrow();
  737.                   if (gchar_cursor() == NUL)        /* delete newline */
  738.                 {
  739.                     temp = curwin->w_cursor.col;
  740.                     if (!p_bs ||                /* only if 'bs' set */
  741.                         u_save((linenr_t)(curwin->w_cursor.lnum - 1),
  742.                             (linenr_t)(curwin->w_cursor.lnum + 2)) == FAIL ||
  743.                                 do_join(FALSE, TRUE) == FAIL)
  744.                         beep_flush();
  745.                     else
  746.                         curwin->w_cursor.col = temp;
  747.                 }
  748.                 else if (delchar(FALSE) == FAIL)/* delete char under cursor */
  749.                     beep_flush();
  750.                 did_ai = FALSE;
  751.                 did_si = FALSE;
  752.                 can_si = FALSE;
  753.                 can_si_back = FALSE;
  754.                 AppendCharToRedobuff(c);
  755.                 goto redraw;
  756.  
  757.               case K_BS:
  758.               case Ctrl('H'):
  759.                 mode = BACKSPACE_CHAR;
  760. dodel:
  761.                 /* can't delete anything in an empty file */
  762.                 /* can't backup past first character in buffer */
  763.                 /* can't backup past starting point unless 'backspace' > 1 */
  764.                 /* can backup to a previous line if 'backspace' == 0 */
  765.                 if (bufempty() || (
  766. #ifdef RIGHTLEFT
  767.                         !revins &&
  768. #endif
  769.                         ((curwin->w_cursor.lnum == 1 &&
  770.                                     curwin->w_cursor.col <= 0) ||
  771.                         (p_bs < 2 && (arrow_used ||
  772.                             (curwin->w_cursor.lnum == Insstart.lnum &&
  773.                             curwin->w_cursor.col <= Insstart.col) ||
  774.                             (curwin->w_cursor.col <= 0 && p_bs == 0))))))
  775.                 {
  776.                     beep_flush();
  777.                     goto redraw;
  778.                 }
  779.  
  780.                 stop_arrow();
  781. #ifdef CINDENT
  782.                 if (inindent(0))
  783.                     can_cindent = FALSE;
  784. #endif
  785. #ifdef RIGHTLEFT
  786.                 if (revins)            /* put cursor after last inserted char */
  787.                     inc_cursor();
  788. #endif
  789.                 if (curwin->w_cursor.col <= 0)        /* delete newline! */
  790.                 {
  791.                     lnum = Insstart.lnum;
  792.                     if (curwin->w_cursor.lnum == Insstart.lnum
  793. #ifdef RIGHTLEFT
  794.                                     || revins
  795. #endif
  796.                                                 )
  797.                     {
  798.                         if (u_save((linenr_t)(curwin->w_cursor.lnum - 2),
  799.                                 (linenr_t)(curwin->w_cursor.lnum + 1)) == FAIL)
  800.                             goto redraw;
  801.                         --Insstart.lnum;
  802.                         Insstart.col = 0;
  803.                     }
  804.                     /*
  805.                      * In replace mode:
  806.                      * cc < 0: NL was inserted, delete it
  807.                      * cc >= 0: NL was replaced, put original characters back
  808.                      */
  809.                     cc = -1;
  810.                     if (State == REPLACE)
  811.                         cc = replace_pop();
  812.                 /* in replace mode, in the line we started replacing, we
  813.                                                         only move the cursor */
  814.                     if (State != REPLACE || curwin->w_cursor.lnum > lnum)
  815.                     {
  816.                         temp = gchar_cursor();        /* remember current char */
  817.                         --curwin->w_cursor.lnum;
  818.                         (void)do_join(FALSE, curs_rows() == OK);
  819.                         if (temp == NUL && gchar_cursor() != NUL)
  820.                             ++curwin->w_cursor.col;
  821.                         /*
  822.                          * in REPLACE mode we have to put back the text that
  823.                          * was replace by the NL. On the replace stack is
  824.                          * first a NUL-terminated sequence of characters that
  825.                          * were deleted and then the character that NL
  826.                          * replaced.
  827.                          */
  828.                         if (State == REPLACE)
  829.                         {
  830.                             /*
  831.                              * Do the next ins_char() in NORMAL state, to
  832.                              * prevent ins_char() from replacing characters and
  833.                              * avoiding showmatch().
  834.                              */
  835.                             State = NORMAL;
  836.                             /*
  837.                              * restore blanks deleted after cursor
  838.                              */
  839.                             while (cc > 0)
  840.                             {
  841.                                 temp = curwin->w_cursor.col;
  842.                                 ins_char(cc);
  843.                                 curwin->w_cursor.col = temp;
  844.                                 cc = replace_pop();
  845.                             }
  846.                             cc = replace_pop();
  847.                             if (cc > 0)
  848.                             {
  849.                                 ins_char(cc);
  850.                                 dec_cursor();
  851.                             }
  852.                             State = REPLACE;
  853.                         }
  854.                     }
  855.                     else
  856.                         dec_cursor();
  857.                     did_ai = FALSE;
  858.                 }
  859.                 else
  860.                 {
  861. #ifdef RIGHTLEFT
  862.                     if (revins)            /* put cursor on last inserted char */
  863.                         dec_cursor();
  864. #endif
  865.                     mincol = 0;
  866.                                                             /* keep indent */
  867.                     if (mode == BACKSPACE_LINE && curbuf->b_p_ai
  868. #ifdef RIGHTLEFT
  869.                             && !revins
  870. #endif
  871.                                         )
  872.                     {
  873.                         temp = curwin->w_cursor.col;
  874.                         beginline(TRUE);
  875.                         if (curwin->w_cursor.col < (colnr_t)temp)
  876.                             mincol = curwin->w_cursor.col;
  877.                         curwin->w_cursor.col = temp;
  878.                     }
  879.  
  880.                     /* delete upto starting point, start of line or previous
  881.                      * word */
  882.                     do
  883.                     {
  884. #ifdef RIGHTLEFT
  885.                         if (!revins)    /* put cursor on char to be deleted */
  886. #endif
  887.                             dec_cursor();
  888.  
  889.                                 /* start of word? */
  890.                         if (mode == BACKSPACE_WORD &&
  891.                                                 !vim_isspace(gchar_cursor()))
  892.                         {
  893.                             mode = BACKSPACE_WORD_NOT_SPACE;
  894.                             temp = iswordchar(gchar_cursor());
  895.                         }
  896.                                 /* end of word? */
  897.                         else if (mode == BACKSPACE_WORD_NOT_SPACE &&
  898.                                           (vim_isspace(cc = gchar_cursor()) ||
  899.                                                       iswordchar(cc) != temp))
  900.                         {
  901. #ifdef RIGHTLEFT
  902.                             if (!revins)
  903. #endif
  904.                                 inc_cursor();
  905. #ifdef RIGHTLEFT
  906.                             else if (State == REPLACE)
  907.                                 dec_cursor();
  908. #endif
  909.                             break;
  910.                         }
  911.                         if (State == REPLACE)
  912.                         {
  913.                             /*
  914.                              * cc < 0: replace stack empty, just move cursor
  915.                              * cc == 0: character was inserted, delete it
  916.                              * cc > 0: character was replace, put original back
  917.                              */
  918.                             cc = replace_pop();
  919.                             if (cc > 0)
  920.                                 pchar_cursor(cc);
  921.                             else if (cc == 0)
  922.                                 (void)delchar(FALSE);
  923.                         }
  924.                         else  /* State != REPLACE */
  925.                         {
  926.                             (void)delchar(FALSE);
  927. #ifdef RIGHTLEFT
  928.                             if (revinschars)
  929.                             {
  930.                                 revinschars--;
  931.                                 revinslegal++;
  932.                             }
  933.                             if (revins && gchar_cursor() == NUL)
  934.                                 break;
  935. #endif
  936.                         }
  937.                         /* Just a single backspace?: */
  938.                         if (mode == BACKSPACE_CHAR)
  939.                             break;
  940.                     } while (
  941. #ifdef RIGHTLEFT
  942.                             revins ||
  943. #endif
  944.                             (curwin->w_cursor.col > mincol &&
  945.                             (curwin->w_cursor.lnum != Insstart.lnum ||
  946.                             curwin->w_cursor.col != Insstart.col)));
  947.                     did_backspace = TRUE;
  948.                 }
  949.                 did_si = FALSE;
  950.                 can_si = FALSE;
  951.                 can_si_back = FALSE;
  952.                 if (curwin->w_cursor.col <= 1)
  953.                     did_ai = FALSE;
  954.                 /*
  955.                  * It's a little strange to put backspaces into the redo
  956.                  * buffer, but it makes auto-indent a lot easier to deal
  957.                  * with.
  958.                  */
  959.                 AppendCharToRedobuff(c);
  960. redraw:
  961.                 need_redraw = TRUE;
  962.                 break;
  963.  
  964.               case Ctrl('W'):        /* delete word before cursor */
  965.                   mode = BACKSPACE_WORD;
  966.                   goto dodel;
  967.  
  968.               case Ctrl('U'):        /* delete inserted text in current line */
  969.                 mode = BACKSPACE_LINE;
  970.                   goto dodel;
  971.  
  972. #ifdef USE_MOUSE
  973.               case K_LEFTMOUSE:
  974.               case K_LEFTDRAG:
  975.               case K_LEFTRELEASE:
  976.               case K_MIDDLEMOUSE:
  977.               case K_MIDDLEDRAG:
  978.               case K_MIDDLERELEASE:
  979.               case K_RIGHTMOUSE:
  980.               case K_RIGHTDRAG:
  981.               case K_RIGHTRELEASE:
  982. #ifdef USE_GUI
  983.                 /* When GUI is active, also move/paste when 'mouse' is empty */
  984.                 if (!gui.in_use)
  985. #endif
  986.                     if (!mouse_has(MOUSE_INSERT))
  987.                         break;
  988.  
  989.                 undisplay_dollar();
  990.                 tpos = curwin->w_cursor;
  991.                 if (do_mouse(c, BACKWARD, 1L, FALSE))
  992.                 {
  993.                     start_arrow(&tpos);
  994. # ifdef CINDENT
  995.                     can_cindent = TRUE;
  996. # endif
  997.                 }
  998.  
  999.                 break;
  1000.  
  1001.               case K_IGNORE:
  1002.                 break;
  1003. #endif
  1004.  
  1005. #ifdef USE_GUI
  1006.               case K_SCROLLBAR:
  1007.                 undisplay_dollar();
  1008.                 tpos = curwin->w_cursor;
  1009.                 if (gui_do_scroll())
  1010.                 {
  1011.                     start_arrow(&tpos);
  1012. # ifdef CINDENT
  1013.                     can_cindent = TRUE;
  1014. # endif
  1015.                 }
  1016.                 break;
  1017.  
  1018.               case K_HORIZ_SCROLLBAR:
  1019.                 undisplay_dollar();
  1020.                 tpos = curwin->w_cursor;
  1021.                 if (gui_do_horiz_scroll())
  1022.                 {
  1023.                     start_arrow(&tpos);
  1024. #ifdef CINDENT
  1025.                     can_cindent = TRUE;
  1026. #endif
  1027.                 }
  1028.                 break;
  1029. #endif
  1030.  
  1031.               case K_LEFT:
  1032.                 undisplay_dollar();
  1033.                 tpos = curwin->w_cursor;
  1034.                   if (oneleft() == OK)
  1035.                 {
  1036.                     start_arrow(&tpos);
  1037. #ifdef RIGHTLEFT
  1038.                     /* If exit reversed string, position is fixed */
  1039.                     if (revinsscol != -1 &&
  1040.                                       (int)curwin->w_cursor.col >= revinsscol)
  1041.                         revinslegal++;
  1042.                     revinschars++;
  1043. #endif
  1044.                 }
  1045.  
  1046.                 /*
  1047.                  * if 'whichwrap' set for cursor in insert mode may go to
  1048.                  * previous line
  1049.                  */
  1050.                 else if (vim_strchr(p_ww, '[') != NULL &&
  1051.                                                     curwin->w_cursor.lnum > 1)
  1052.                 {
  1053.                     start_arrow(&tpos);
  1054.                     --(curwin->w_cursor.lnum);
  1055.                     coladvance(MAXCOL);
  1056.                     curwin->w_set_curswant = TRUE;    /* so we stay at the end */
  1057.                 }
  1058.                 else
  1059.                     beep_flush();
  1060.                 break;
  1061.  
  1062.               case K_HOME:
  1063.                 undisplay_dollar();
  1064.                 tpos = curwin->w_cursor;
  1065.                 if ((mod_mask & MOD_MASK_CTRL))
  1066.                     curwin->w_cursor.lnum = 1;
  1067.                   curwin->w_cursor.col = 0;
  1068.                 curwin->w_curswant = 0;
  1069.                 start_arrow(&tpos);
  1070.                 break;
  1071.  
  1072.               case K_END:
  1073.                 undisplay_dollar();
  1074.                 tpos = curwin->w_cursor;
  1075.                 if ((mod_mask & MOD_MASK_CTRL))
  1076.                     curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  1077.                 coladvance(MAXCOL);
  1078.                 curwin->w_curswant = MAXCOL;
  1079.                 start_arrow(&tpos);
  1080.                 break;
  1081.  
  1082.               case K_S_LEFT:
  1083.                 undisplay_dollar();
  1084.                   if (curwin->w_cursor.lnum > 1 || curwin->w_cursor.col > 0)
  1085.                 {
  1086.                     start_arrow(&curwin->w_cursor);
  1087.                     (void)bck_word(1L, 0, FALSE);
  1088.                 }
  1089.                 else
  1090.                     beep_flush();
  1091.                 break;
  1092.  
  1093.               case K_RIGHT:
  1094.                 undisplay_dollar();
  1095.                 if (gchar_cursor() != NUL)
  1096.                 {
  1097.                     start_arrow(&curwin->w_cursor);
  1098.                     curwin->w_set_curswant = TRUE;
  1099.                     ++curwin->w_cursor.col;
  1100. #ifdef RIGHTLEFT
  1101.                     revinslegal++;
  1102.                     if (revinschars)
  1103.                         revinschars--;
  1104. #endif
  1105.                 }
  1106.                     /* if 'whichwrap' set for cursor in insert mode may go
  1107.                      * to next line */
  1108.                 else if (vim_strchr(p_ww, ']') != NULL &&
  1109.                            curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
  1110.                 {
  1111.                     start_arrow(&curwin->w_cursor);
  1112.                     curwin->w_set_curswant = TRUE;
  1113.                     ++curwin->w_cursor.lnum;
  1114.                     curwin->w_cursor.col = 0;
  1115.                 }
  1116.                 else
  1117.                     beep_flush();
  1118.                 break;
  1119.  
  1120.               case K_S_RIGHT:
  1121.                 undisplay_dollar();
  1122.                   if (curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count ||
  1123.                                                         gchar_cursor() != NUL)
  1124.                 {
  1125.                     start_arrow(&curwin->w_cursor);
  1126.                     (void)fwd_word(1L, 0, 0);
  1127.                 }
  1128.                 else
  1129.                     beep_flush();
  1130.                 break;
  1131.  
  1132.               case K_UP:
  1133.                 undisplay_dollar();
  1134.                 tpos = curwin->w_cursor;
  1135.                   if (cursor_up(1L) == OK)
  1136.                 {
  1137.                     start_arrow(&tpos);
  1138. #ifdef CINDENT
  1139.                     can_cindent = TRUE;
  1140. #endif
  1141.                 }
  1142.                 else
  1143.                     beep_flush();
  1144.                 break;
  1145.  
  1146.               case K_S_UP:
  1147.               case K_PAGEUP:
  1148.                 undisplay_dollar();
  1149.                 tpos = curwin->w_cursor;
  1150.                   if (onepage(BACKWARD, 1L) == OK)
  1151.                 {
  1152.                     start_arrow(&tpos);
  1153. #ifdef CINDENT
  1154.                     can_cindent = TRUE;
  1155. #endif
  1156.                 }
  1157.                 else
  1158.                     beep_flush();
  1159.                 break;
  1160.  
  1161.               case K_DOWN:
  1162.                 undisplay_dollar();
  1163.                 tpos = curwin->w_cursor;
  1164.                   if (cursor_down(1L) == OK)
  1165.                 {
  1166.                     start_arrow(&tpos);
  1167. #ifdef CINDENT
  1168.                     can_cindent = TRUE;
  1169. #endif
  1170.                 }
  1171.                 else
  1172.                     beep_flush();
  1173.                 break;
  1174.  
  1175.               case K_S_DOWN:
  1176.               case K_PAGEDOWN:
  1177.                 undisplay_dollar();
  1178.                 tpos = curwin->w_cursor;
  1179.                   if (onepage(FORWARD, 1L) == OK)
  1180.                 {
  1181.                     start_arrow(&tpos);
  1182. #ifdef CINDENT
  1183.                     can_cindent = TRUE;
  1184. #endif
  1185.                 }
  1186.                 else
  1187.                     beep_flush();
  1188.                 break;
  1189.  
  1190.               case TAB:                /* TAB or Complete patterns along path */
  1191. #ifdef INSERT_EXPAND
  1192.                 if (ctrl_x_mode == CTRL_X_PATH_PATTERNS)
  1193.                     goto docomplete;
  1194. #endif /* INSERT_EXPAND */
  1195.  
  1196.                 if (Insstart_blank_vcol == MAXCOL &&
  1197.                                        curwin->w_cursor.lnum == Insstart.lnum)
  1198.                     Insstart_blank_vcol = curwin->w_virtcol;
  1199.                 if (echeck_abbr(TAB + ABBR_OFF))
  1200.                     break;
  1201.                 i = inindent(0);
  1202. #ifdef CINDENT
  1203.                 if (i)
  1204.                     can_cindent = FALSE;
  1205. #endif
  1206.                   if (!curbuf->b_p_et && !(p_sta && i))
  1207.                     goto normalchar;
  1208.  
  1209.                 stop_arrow();
  1210.                 did_ai = FALSE;
  1211.                 did_si = FALSE;
  1212.                 can_si = FALSE;
  1213.                 can_si_back = FALSE;
  1214.                 AppendToRedobuff((char_u *)"\t");
  1215.  
  1216.                 if (p_sta && i)                    /* insert tab in indent */
  1217.                 {
  1218.                     change_indent(INDENT_INC, 0, p_sr);
  1219.                     goto redraw;
  1220.                 }
  1221.  
  1222.                 /*
  1223.                  * p_et is set: expand a tab into spaces
  1224.                  */
  1225.                 temp = (int)curbuf->b_p_ts;
  1226.                 temp -= curwin->w_virtcol % temp;
  1227.  
  1228.                 /*
  1229.                  * insert the first space with ins_char(); it will delete one
  1230.                  * char in replace mode. Insert the rest with ins_str(); it
  1231.                  * will not delete any chars
  1232.                  */
  1233.                 ins_char(' ');
  1234.                 while (--temp)
  1235.                 {
  1236.                     ins_str((char_u *)" ");
  1237.                     if (State == REPLACE)        /* no char replaced */
  1238.                         replace_push(NUL);
  1239.                 }
  1240.                 goto redraw;
  1241.  
  1242.               case CR:
  1243.               case NL:
  1244.                 if (echeck_abbr(c + ABBR_OFF))
  1245.                     break;
  1246.                 stop_arrow();
  1247.                 if (State == REPLACE)
  1248.                     replace_push(NUL);
  1249. #ifdef RIGHTLEFT
  1250.                 /* NL in reverse insert will allways start in the end of
  1251.                  * current line. */
  1252.                 if (revins)
  1253.                     while (gchar_cursor() != NUL)
  1254.                         ++curwin->w_cursor.col;
  1255. #endif
  1256.  
  1257.                 AppendToRedobuff(NL_STR);
  1258.                 if (has_format_option(FO_RET_COMS))
  1259.                     fo_do_comments = TRUE;
  1260.                 i = Opencmd(FORWARD, TRUE, FALSE);
  1261.                 fo_do_comments = FALSE;
  1262. #ifdef CINDENT
  1263.                 can_cindent = TRUE;
  1264. #endif
  1265.                 if (!i)
  1266.                     goto doESCkey;        /* out of memory */
  1267.                 break;
  1268.  
  1269. #ifdef DIGRAPHS
  1270.               case Ctrl('K'):
  1271. #ifdef INSERT_EXPAND
  1272.                 if (ctrl_x_mode == CTRL_X_DICTIONARY)
  1273.                     goto docomplete;
  1274. #endif
  1275.                 if (NextScreen != NULL)
  1276.                     screen_outchar('?', curwin->w_winpos + curwin->w_row,
  1277. #ifdef RIGHTLEFT
  1278.                         curwin->w_p_rl ? (int)Columns - 1 - curwin->w_col :
  1279. #endif
  1280.                                                             curwin->w_col);
  1281.                 if (!add_to_showcmd(c, FALSE))
  1282.                     setcursor();
  1283.                     /* don't map the digraph chars. This also prevents the
  1284.                      * mode message to be deleted when ESC is hit */
  1285.                 ++no_mapping;
  1286.                 ++allow_keys;
  1287.                   c = vgetc();
  1288.                 --no_mapping;
  1289.                 --allow_keys;
  1290.                 if (IS_SPECIAL(c))        /* special key */
  1291.                 {
  1292.                     clear_showcmd();
  1293.                     insert_special(c, TRUE);
  1294.                     need_redraw = TRUE;
  1295.                     break;
  1296.                 }
  1297.                 if (c != ESC)
  1298.                 {
  1299.                     if (charsize(c) == 1 && NextScreen != NULL)
  1300.                          screen_outchar(c, curwin->w_winpos + curwin->w_row,
  1301. #ifdef RIGHTLEFT
  1302.                             curwin->w_p_rl ? (int)Columns - 1 - curwin->w_col :
  1303. #endif
  1304.                                                                 curwin->w_col);
  1305.                     if (!add_to_showcmd(c, FALSE))
  1306.                         setcursor();
  1307.                     ++no_mapping;
  1308.                     ++allow_keys;
  1309.                     cc = vgetc();
  1310.                     --no_mapping;
  1311.                     --allow_keys;
  1312.                     if (cc != ESC)
  1313.                     {
  1314.                         AppendToRedobuff((char_u *)"\026");    /* CTRL-V */
  1315.                         c = getdigraph(c, cc, TRUE);
  1316.                         clear_showcmd();
  1317.                         goto normalchar;
  1318.                     }
  1319.                 }
  1320.                 clear_showcmd();
  1321.                 need_redraw = TRUE;
  1322.                 break;
  1323. #else /* DIGRAPHS */
  1324. # ifdef INSERT_EXPAND
  1325.               case Ctrl('K'):
  1326.                 if (ctrl_x_mode != CTRL_X_DICTIONARY)
  1327.                     goto normalchar;
  1328.                 goto docomplete;
  1329. # endif /* INSERT_EXPAND */
  1330. #endif /* DIGRAPHS */
  1331.  
  1332. #ifdef INSERT_EXPAND
  1333.               case Ctrl(']'):            /* Tag name completion after ^X */
  1334.                 if (ctrl_x_mode != CTRL_X_TAGS)
  1335.                     goto normalchar;
  1336.                 goto docomplete;
  1337.  
  1338.               case Ctrl('F'):            /* File name completion after ^X */
  1339.                 if (ctrl_x_mode != CTRL_X_FILES)
  1340.                     goto normalchar;
  1341.                 goto docomplete;
  1342.  
  1343.               case Ctrl('L'):            /* Whole line completion after ^X */
  1344.                 if (ctrl_x_mode != CTRL_X_WHOLE_LINE)
  1345.                     goto normalchar;
  1346.                 /* FALLTHROUGH */
  1347.  
  1348.               case Ctrl('P'):            /* Do previous pattern completion */
  1349.               case Ctrl('N'):            /* Do next pattern completion */
  1350. docomplete:
  1351.                 if (c == Ctrl('P') || c == Ctrl('L'))
  1352.                     complete_direction = BACKWARD;
  1353.                 else
  1354.                     complete_direction = FORWARD;
  1355.                 quick_m = mesg = NULL;            /* No message by default */
  1356.                 if (!started_completion)
  1357.                 {
  1358.                     /* First time we hit ^N or ^P (in a row, I mean) */
  1359.  
  1360.                     /* Turn off 'sm' so we don't show matches with ^X^L */
  1361.                     save_sm = p_sm;
  1362.                     p_sm = FALSE;
  1363.  
  1364.                     if (ctrl_x_mode == 0)
  1365.                     {
  1366.                         edit_submode = (char_u *)" Keyword completion (^P/^N)";
  1367.                         showmode();
  1368.                     }
  1369.                     did_ai = FALSE;
  1370.                     did_si = FALSE;
  1371.                     can_si = FALSE;
  1372.                     can_si_back = FALSE;
  1373.                     stop_arrow();
  1374.                     done_dir = 0;
  1375.                     first_match_pos = curwin->w_cursor;
  1376.                     ptr = tmp_ptr = ml_get(first_match_pos.lnum);
  1377.                     complete_col = first_match_pos.col;
  1378.                     temp = (int)complete_col - 1;
  1379.  
  1380.                     /* Work out completion pattern and original text -- webb */
  1381.                     if (ctrl_x_mode == 0 || (ctrl_x_mode & CTRL_X_WANT_IDENT))
  1382.                     {
  1383.                         if (temp < 0 || !iswordchar(ptr[temp]))
  1384.                         {
  1385.                             /* Match any word of at least two chars */
  1386.                             complete_pat = strsave((char_u *)"\\<\\k\\k");
  1387.                             if (complete_pat == NULL)
  1388.                                 break;
  1389.                             tmp_ptr += complete_col;
  1390.                             temp = 0;
  1391.                         }
  1392.                         else
  1393.                         {
  1394.                             while (temp >= 0 && iswordchar(ptr[temp]))
  1395.                                 temp--;
  1396.                             tmp_ptr += ++temp;
  1397.                             if ((temp = (int)complete_col - temp) == 1)
  1398.                             {
  1399.                                 /* Only match word with at least two
  1400.                                  * chars -- webb
  1401.                                  */
  1402.                                 sprintf((char *)IObuff, "\\<%c\\k", *tmp_ptr);
  1403.                                 complete_pat = strsave(IObuff);
  1404.                                 if (complete_pat == NULL)
  1405.                                     break;
  1406.                             }
  1407.                             else
  1408.                             {
  1409.                                 complete_pat = alloc(temp + 3);
  1410.                                 if (complete_pat == NULL)
  1411.                                     break;
  1412.                                 sprintf((char *)complete_pat, "\\<%.*s", temp,
  1413.                                                                     tmp_ptr);
  1414.                             }
  1415.                         }
  1416.                     }
  1417.                     else if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
  1418.                     {
  1419.                         tmp_ptr = skipwhite(ptr);
  1420.                         temp = (int)complete_col - (tmp_ptr - ptr);
  1421.                         complete_pat = strnsave(tmp_ptr, temp);
  1422.                         if (complete_pat == NULL)
  1423.                             break;
  1424.                     }
  1425.                     else if (ctrl_x_mode == CTRL_X_FILES)
  1426.                     {
  1427.                         while (temp >= 0 && isfilechar(ptr[temp]))
  1428.                             temp--;
  1429.                         tmp_ptr += ++temp;
  1430.                         temp = (int)complete_col - temp;
  1431.                         complete_pat = addstar(tmp_ptr, temp);
  1432.                         if (complete_pat == NULL)
  1433.                             break;
  1434.                     }
  1435.                     original_text = strnsave(tmp_ptr, temp);
  1436.                     if (original_text == NULL)
  1437.                     {
  1438.                         vim_free(complete_pat);
  1439.                         complete_pat = NULL;
  1440.                         break;
  1441.                     }
  1442.  
  1443.                     complete_col = tmp_ptr - ptr;
  1444.                     first_match_pos.col -= temp;
  1445.  
  1446.                     /* So that ^N can match word immediately after cursor */
  1447.                     if (ctrl_x_mode == 0)
  1448.                         dec(&first_match_pos);
  1449.  
  1450.                     last_match_pos = first_match_pos;
  1451.  
  1452.                     /* Get list of all completions now, if appropriate */
  1453.                     if (ctrl_x_mode == CTRL_X_PATH_PATTERNS ||
  1454.                         ctrl_x_mode == CTRL_X_PATH_DEFINES)
  1455.                     {
  1456.                         started_completion = TRUE;
  1457.                         find_pattern_in_path(complete_pat,
  1458.                                 (int)STRLEN(complete_pat), FALSE, FALSE,
  1459.                             (ctrl_x_mode == CTRL_X_PATH_DEFINES) ? FIND_DEFINE
  1460.                             : FIND_ANY, 1L, ACTION_EXPAND,
  1461.                             (linenr_t)1, (linenr_t)MAXLNUM);
  1462.  
  1463.                         if (make_cyclic() > 1)
  1464.                         {
  1465.                             sprintf((char *)IObuff, "There are %d matches",
  1466.                                 count_completions());
  1467.                             mesg = IObuff;
  1468.                         }
  1469.                     }
  1470.                     else if (ctrl_x_mode == CTRL_X_DICTIONARY)
  1471.                     {
  1472.                         started_completion = TRUE;
  1473.                         if (*p_dict == NUL)
  1474.                             mesg = (char_u *)"'dictionary' option is empty";
  1475.                         else
  1476.                         {
  1477.                             complete_dictionaries(complete_pat,
  1478.                                                           complete_direction);
  1479.                             if (make_cyclic() > 1)
  1480.                             {
  1481.                                 sprintf((char *)IObuff,
  1482.                                     "There are %d matching words",
  1483.                                     count_completions());
  1484.                                 mesg = IObuff;
  1485.                             }
  1486.                         }
  1487.                     }
  1488.                     else if (ctrl_x_mode == CTRL_X_TAGS)
  1489.                     {
  1490.                         started_completion = TRUE;
  1491.                             /* set reg_ic according to p_ic, p_scs and pat */
  1492.                         set_reg_ic(complete_pat);
  1493.                         prog = vim_regcomp(complete_pat);
  1494.                         if (prog != NULL &&
  1495.                             find_tags(NULL, prog, &num_matches, &matches, FALSE)
  1496.                                                     == OK && num_matches > 0)
  1497.                         {
  1498.                             for (i = 0; i < num_matches; i++)
  1499.                                 if (add_completion(matches[i], -1, NULL,
  1500.                                                         FORWARD) == RET_ERROR)
  1501.                                     break;
  1502.                             FreeWild(num_matches, matches);
  1503.                             vim_free(prog);
  1504.                             if (make_cyclic() > 1)
  1505.                             {
  1506.                                 sprintf((char *)IObuff,
  1507.                                     "There are %d matching tags",
  1508.                                     count_completions());
  1509.                                 mesg = IObuff;
  1510.                             }
  1511.                         }
  1512.                         else
  1513.                         {
  1514.                             vim_free(prog);
  1515.                             vim_free(complete_pat);
  1516.                             complete_pat = NULL;
  1517.                         }
  1518.                     }
  1519.                     else if (ctrl_x_mode == CTRL_X_FILES)
  1520.                     {
  1521.                         started_completion = TRUE;
  1522.                         expand_interactively = TRUE;
  1523.                         if (ExpandWildCards(1, &complete_pat, &num_matches,
  1524.                                                 &matches, FALSE, FALSE) == OK)
  1525.                         {
  1526.                             for (i = 0; i < num_matches; i++)
  1527.                                 if (add_completion(matches[i], -1, NULL,
  1528.                                                         FORWARD) == RET_ERROR)
  1529.                                     break;
  1530.                             FreeWild(num_matches, matches);
  1531.                             if (make_cyclic() > 1)
  1532.                             {
  1533.                                 sprintf((char *)IObuff,
  1534.                                     "There are %d matching file names",
  1535.                                     count_completions());
  1536.                                 mesg = IObuff;
  1537.                             }
  1538.                         }
  1539.                         else
  1540.                         {
  1541.                             vim_free(complete_pat);
  1542.                             complete_pat = NULL;
  1543.                         }
  1544.                         expand_interactively = FALSE;
  1545.                     }
  1546.                 }
  1547.                 /*
  1548.                  * In insert mode: Delete the typed part.
  1549.                  * In replace mode: Put the old characters back, if any.
  1550.                  */
  1551.                 while (curwin->w_cursor.col > complete_col)
  1552.                 {
  1553.                     curwin->w_cursor.col--;
  1554.                     if (State == REPLACE)
  1555.                     {
  1556.                         if ((cc = replace_pop()) > 0)
  1557.                             pchar(curwin->w_cursor, cc);
  1558.                     }
  1559.                     else
  1560.                         delchar(FALSE);
  1561.                 }
  1562.                 complete_pos = NULL;
  1563.                 if (started_completion && curr_match == NULL &&
  1564.                                         (p_ws || done_dir == BOTH_DIRECTIONS))
  1565.                     quick_m = e_patnotf;
  1566.                 else if (curr_match != NULL && complete_direction == FORWARD &&
  1567.                                             curr_match->next != NULL)
  1568.                     curr_match = curr_match->next;
  1569.                 else if (curr_match != NULL && complete_direction == BACKWARD &&
  1570.                                             curr_match->prev != NULL)
  1571.                     curr_match = curr_match->prev;
  1572.                 else
  1573.                 {
  1574.                     complete_pos = (complete_direction == FORWARD) ?
  1575.                                         &last_match_pos : &first_match_pos;
  1576.                     /*
  1577.                      * If 'infercase' is set, don't use 'smartcase' here
  1578.                      */
  1579.                     save_p_scs = p_scs;
  1580.                     if (curbuf->b_p_inf)
  1581.                         p_scs = FALSE;
  1582.                     for (;;)
  1583.                     {
  1584.                         if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
  1585.                             temp = search_for_exact_line(complete_pos,
  1586.                                     complete_direction, complete_pat);
  1587.                         else
  1588.                             temp = searchit(complete_pos, complete_direction,
  1589.                                     complete_pat, 1L,
  1590.                                     SEARCH_KEEP + SEARCH_NFMSG, RE_LAST);
  1591.                         if (temp == FAIL)
  1592.                         {
  1593.                             if (!p_ws && done_dir != -complete_direction)
  1594.                             {
  1595.                                 /*
  1596.                                  * With nowrapscan, we haven't finished
  1597.                                  * looking in the other direction yet -- webb
  1598.                                  */
  1599.                                 temp = OK;
  1600.                                 done_dir = complete_direction;
  1601.                             }
  1602.                             else if (!p_ws)
  1603.                                 done_dir = BOTH_DIRECTIONS;
  1604.                             break;
  1605.                         }
  1606.                         if (!started_completion)
  1607.                         {
  1608.                             started_completion = TRUE;
  1609.                             first_match_pos = *complete_pos;
  1610.                             last_match_pos = *complete_pos;
  1611.                         }
  1612.                         else if (first_match_pos.lnum == last_match_pos.lnum &&
  1613.                           first_match_pos.col == last_match_pos.col)
  1614.                         {
  1615.                             /* We have found all the matches in this file */
  1616.                             temp = FAIL;
  1617.                             break;
  1618.                         }
  1619.                         ptr = ml_get_pos(complete_pos);
  1620.                         if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
  1621.                             temp = STRLEN(ptr);
  1622.                         else
  1623.                         {
  1624.                             tmp_ptr = ptr;
  1625.                             temp = 0;
  1626.                             while (*tmp_ptr != NUL && iswordchar(*tmp_ptr++))
  1627.                                 temp++;
  1628.                         }
  1629.                         if (add_completion_and_infercase(ptr, temp, NULL,
  1630.                                                   complete_direction) != FAIL)
  1631.                         {
  1632.                             temp = OK;
  1633.                             break;
  1634.                         }
  1635.                     }
  1636.                     p_scs = save_p_scs;
  1637.                 }
  1638.                 if (complete_pos != NULL && temp == FAIL)
  1639.                 {
  1640.                     int tot;
  1641.  
  1642.                     tot = count_completions();    /* Total num matches */
  1643.                     if (curr_match != NULL)
  1644.                         (void)make_cyclic();
  1645.                     if (tot > 1)
  1646.                     {
  1647.                         sprintf((char *)IObuff,
  1648.                             "All %d matches have now been found", tot);
  1649.                         mesg = IObuff;
  1650.                     }
  1651.                     else if (tot == 0)
  1652.                         quick_m = e_patnotf;
  1653.                 }
  1654.  
  1655.                 /* eat the ESC to avoid leaving insert mode */
  1656.                 if (got_int)
  1657.                 {
  1658.                     (void)vgetc();
  1659.                     got_int = FALSE;
  1660.                 }
  1661.  
  1662.                 /*
  1663.                  * When using match from another file, show the file name.
  1664.                  */
  1665.                 if (curr_match != NULL)
  1666.                     ptr = curr_match->str;
  1667.                 else            /* back to what has been typed */
  1668.                     ptr = original_text;
  1669.  
  1670.                 if (curr_match == NULL || curr_match->original)
  1671.                 {
  1672.                     edit_submode_extra = (char_u *)"Back at original";
  1673.                     edit_submode_highl = TRUE;
  1674.                 }
  1675.                 else if (first_match != NULL && first_match->next != NULL &&
  1676.                                           (first_match->next == first_match ||
  1677.                                                   first_match->next->original))
  1678.                 {
  1679.                     edit_submode_extra = (char_u *)"(the only match)";
  1680.                     edit_submode_highl = FALSE;
  1681.                 }
  1682.  
  1683.                 /*
  1684.                  * Use ins_char() to insert the text, it is a bit slower than
  1685.                  * ins_str(), but it takes care of replace mode.
  1686.                  */
  1687.                 if (ptr != NULL)
  1688.                     while (*ptr)
  1689.                         ins_char(*ptr++);
  1690.  
  1691.                 started_completion = TRUE;
  1692.                 need_redraw = TRUE;
  1693.                 (void)set_highlight('r');
  1694.                 msg_highlight = TRUE;
  1695.                 if (mesg != NULL)
  1696.                 {
  1697.                     msg(mesg);
  1698.                     mch_delay(1000L, FALSE);
  1699.                 }
  1700.                 else if (quick_m != NULL)
  1701.                     msg(quick_m);
  1702.                 else if (edit_submode_extra != NULL)
  1703.                     showmode();
  1704.                 edit_submode_extra = NULL;
  1705.                 msg_highlight = FALSE;
  1706.  
  1707.                 /*
  1708.                  * If there is a file name for the match, overwrite any
  1709.                  * previous message, it's more interesting to know where the
  1710.                  * match comes from, except when using the dictionary.
  1711.                  * Truncate the file name to avoid a wait for return.
  1712.                  */
  1713.                 if (curr_match != NULL && curr_match->fname != NULL &&
  1714.                             (ctrl_x_mode != CTRL_X_DICTIONARY ||
  1715.                                            (mesg == NULL && quick_m == NULL)))
  1716.                 {
  1717.                     STRCPY(IObuff, "match in file ");
  1718.                     i = (strsize(curr_match->fname) + 16) - sc_col;
  1719.                     if (i <= 0)
  1720.                         i = 0;
  1721.                     else
  1722.                         STRCAT(IObuff, "<");
  1723.                     STRCAT(IObuff, curr_match->fname + i);
  1724.                     msg(IObuff);
  1725.                 }
  1726.                 break;
  1727. #endif /* INSERT_EXPAND */
  1728.  
  1729.               case Ctrl('Y'):                /* copy from previous line */
  1730. #ifdef INSERT_EXPAND
  1731.                 if (ctrl_x_mode == CTRL_X_SCROLL)
  1732.                 {
  1733.                     scrolldown_clamp();
  1734.                     updateScreen(VALID);
  1735.                     break;
  1736.                 }
  1737. #endif /* INSERT_EXPAND */
  1738.                 lnum = curwin->w_cursor.lnum - 1;
  1739.                 goto copychar;
  1740.  
  1741.               case Ctrl('E'):                /* copy from next line */
  1742. #ifdef INSERT_EXPAND
  1743.                 if (ctrl_x_mode == CTRL_X_SCROLL)
  1744.                 {
  1745.                     scrollup_clamp();
  1746.                     updateScreen(VALID);
  1747.                     break;
  1748.                 }
  1749. #endif /* INSERT_EXPAND */
  1750.                 lnum = curwin->w_cursor.lnum + 1;
  1751. copychar:
  1752.                 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
  1753.                 {
  1754.                     beep_flush();
  1755.                     break;
  1756.                 }
  1757.  
  1758.                 /* try to advance to the cursor column */
  1759.                 temp = 0;
  1760.                 ptr = ml_get(lnum);
  1761.                 while ((colnr_t)temp < curwin->w_virtcol && *ptr)
  1762.                     temp += lbr_chartabsize(ptr++, (colnr_t)temp);
  1763.  
  1764.                 if ((colnr_t)temp > curwin->w_virtcol)
  1765.                     --ptr;
  1766.                 if ((c = *ptr) == NUL)
  1767.                 {
  1768.                     beep_flush();
  1769.                     break;
  1770.                 }
  1771.  
  1772.                 /*FALLTHROUGH*/
  1773.               default:
  1774. normalchar:
  1775.                 /*
  1776.                  * do some very smart indenting when entering '{' or '}'
  1777.                  */
  1778.                 if (((did_si || can_si_back) && c == '{') ||
  1779.                                                          (can_si && c == '}'))
  1780.                 {
  1781.                     FPOS    *pos, old_pos;
  1782.  
  1783.                         /* for '}' set indent equal to indent of line
  1784.                          * containing matching '{'
  1785.                          */
  1786.                     if (c == '}' && (pos = findmatch('{')) != NULL)
  1787.                     {
  1788.                         old_pos = curwin->w_cursor;
  1789.                         /*
  1790.                          * If the matching '{' has a ')' immediately before it
  1791.                          * (ignoring white-space), then line up with the start
  1792.                          * of the line containing the matching '(' if there is
  1793.                          * one.  This handles the case where an
  1794.                          * "if (..\n..) {" statement continues over multiple
  1795.                          * lines -- webb
  1796.                          */
  1797.                         ptr = ml_get(pos->lnum);
  1798.                         i = pos->col;
  1799.                         if (i > 0)            /* skip blanks before '{' */
  1800.                             while (--i > 0 && vim_iswhite(ptr[i]))
  1801.                                 ;
  1802.                         curwin->w_cursor.lnum = pos->lnum;
  1803.                         curwin->w_cursor.col = i;
  1804.                         if (ptr[i] == ')' && (pos = findmatch('(')) != NULL)
  1805.                             curwin->w_cursor = *pos;
  1806.                         i = get_indent();
  1807.                         curwin->w_cursor = old_pos;
  1808.                         set_indent(i, TRUE);
  1809.                     }
  1810.                     else if (curwin->w_cursor.col > 0)
  1811.                     {
  1812.                         /*
  1813.                          * when inserting '{' after "O" reduce indent, but not
  1814.                          * more than indent of previous line
  1815.                          */
  1816.                         temp = TRUE;
  1817.                         if (c == '{' && can_si_back &&
  1818.                                                     curwin->w_cursor.lnum > 1)
  1819.                         {
  1820.                             old_pos = curwin->w_cursor;
  1821.                             i = get_indent();
  1822.                             while (curwin->w_cursor.lnum > 1)
  1823.                             {
  1824.                                 ptr = skipwhite(
  1825.                                            ml_get(--(curwin->w_cursor.lnum)));
  1826.                                 /* ignore empty lines and lines starting with
  1827.                                  * '#'.
  1828.                                  */
  1829.                                 if (*ptr != '#' && *ptr != NUL)
  1830.                                     break;
  1831.                             }
  1832.                             if (get_indent() >= i)
  1833.                                 temp = FALSE;
  1834.                             curwin->w_cursor = old_pos;
  1835.                         }
  1836.                         if (temp)
  1837.                             shift_line(TRUE, FALSE, 1);
  1838.                     }
  1839.                 }
  1840.                     /* set indent of '#' always to 0 */
  1841.                 if (curwin->w_cursor.col > 0 && can_si && c == '#')
  1842.                 {
  1843.                                 /* remember current indent for next line */
  1844.                     old_indent = get_indent();
  1845.                     set_indent(0, TRUE);
  1846.                 }
  1847.  
  1848.                 if (c == ' ')
  1849.                 {
  1850. #ifdef CINDENT
  1851.                     if (inindent(0))
  1852.                         can_cindent = FALSE;
  1853. #endif
  1854.                     if (Insstart_blank_vcol == MAXCOL &&
  1855.                                        curwin->w_cursor.lnum == Insstart.lnum)
  1856.                         Insstart_blank_vcol = curwin->w_virtcol;
  1857.                 }
  1858.  
  1859.                 if (iswordchar(c) || !echeck_abbr(c))
  1860.                 {
  1861.                     insert_special(c, FALSE);
  1862.                     need_redraw = TRUE;
  1863. #ifdef RIGHTLEFT
  1864.                     revinslegal++;
  1865.                     revinschars++;
  1866. #endif
  1867.                 }
  1868.                 break;
  1869.         }    /* end of switch (c) */
  1870.  
  1871. #ifdef CINDENT
  1872.         if (curbuf->b_p_cin && can_cindent
  1873. # ifdef INSERT_EXPAND
  1874.                                             && !ctrl_x_mode
  1875. # endif
  1876.                                                                )
  1877.         {
  1878. force_cindent:
  1879.             /*
  1880.              * Indent now if a key was typed that is in 'cinkeys'.
  1881.              */
  1882.             if (in_cinkeys(c, ' ', line_is_white))
  1883.             {
  1884.                 stop_arrow();
  1885.  
  1886.                 /* re-indent the current line */
  1887.                 fixthisline(get_c_indent);
  1888.  
  1889.                 /* draw the changes on the screen later */
  1890.                 need_redraw = TRUE;
  1891.             }
  1892.         }
  1893. #endif /* CINDENT */
  1894.  
  1895.     }    /* for (;;) */
  1896. }
  1897.  
  1898. /*
  1899.  * Insert an indent (for <Tab> or CTRL-T) or delete an indent (for CTRL-D).
  1900.  * Keep the cursor on the same character.
  1901.  * type == INDENT_INC    increase indent (for CTRL-T or <Tab>)
  1902.  * type == INDENT_DEC    decrease indent (for CTRL-D)
  1903.  * type == INDENT_SET    set indent to "amount"
  1904.  * if round is TRUE, round the indent to 'shiftwidth' (only with _INC and _Dec).
  1905.  */
  1906.     static void
  1907. change_indent(type, amount, round)
  1908.     int        type;
  1909.     int        amount;
  1910.     int        round;
  1911. {
  1912.     int            vcol;
  1913.     int            last_vcol;
  1914.     int            insstart_less;            /* reduction for Insstart.col */
  1915.     int            new_cursor_col;
  1916.     int            i;
  1917.     char_u        *ptr;
  1918.     int            save_p_list;
  1919.  
  1920.     /* for the following tricks we don't want list mode */
  1921.     save_p_list = curwin->w_p_list;
  1922.     if (save_p_list)
  1923.     {
  1924.         curwin->w_p_list = FALSE;
  1925.         curs_columns(FALSE);            /* recompute w_virtcol */
  1926.     }
  1927.     vcol = curwin->w_virtcol;
  1928.  
  1929.     /* determine offset from first non-blank */
  1930.     new_cursor_col = curwin->w_cursor.col;
  1931.     beginline(TRUE);
  1932.     new_cursor_col -= curwin->w_cursor.col;
  1933.  
  1934.     insstart_less = curwin->w_cursor.col;
  1935.  
  1936.     /*
  1937.      * If the cursor is in the indent, compute how many screen columns the
  1938.      * cursor is to the left of the first non-blank.
  1939.      */
  1940.     if (new_cursor_col < 0)
  1941.         vcol = get_indent() - vcol;
  1942.  
  1943.     /*
  1944.      * Set the new indent.  The cursor will be put on the first non-blank.
  1945.      */
  1946.     if (type == INDENT_SET)
  1947.         set_indent(amount, TRUE);
  1948.     else
  1949.         shift_line(type == INDENT_DEC, round, 1);
  1950.     insstart_less -= curwin->w_cursor.col;
  1951.  
  1952.     /*
  1953.      * Try to put cursor on same character.
  1954.      * If the cursor is at or after the first non-blank in the line,
  1955.      * compute the cursor column relative to the column of the first
  1956.      * non-blank character.
  1957.      * If we are not in insert mode, leave the cursor on the first non-blank.
  1958.      * If the cursor is before the first non-blank, position it relative
  1959.      * to the first non-blank, counted in screen columns.
  1960.      */
  1961.     if (new_cursor_col >= 0)
  1962.         new_cursor_col += curwin->w_cursor.col;
  1963.     else if (!(State & INSERT))
  1964.         new_cursor_col = curwin->w_cursor.col;
  1965.     else
  1966.     {
  1967.         /*
  1968.          * Compute the screen column where the cursor should be.
  1969.          */
  1970.         vcol = get_indent() - vcol;
  1971.         curwin->w_virtcol = (vcol < 0) ? 0 : vcol;
  1972.  
  1973.         /*
  1974.          * Advance the cursor until we reach the right screen column.
  1975.          */
  1976.         vcol = last_vcol = 0;
  1977.         new_cursor_col = -1;
  1978.         ptr = ml_get_curline();
  1979.         while (vcol <= (int)curwin->w_virtcol)
  1980.         {
  1981.             last_vcol = vcol;
  1982.             ++new_cursor_col;
  1983.             vcol += lbr_chartabsize(ptr + new_cursor_col, (colnr_t)vcol);
  1984.         }
  1985.         vcol = last_vcol;
  1986.  
  1987.         /*
  1988.          * May need to insert spaces to be able to position the cursor on
  1989.          * the right screen column.
  1990.          */
  1991.         if (vcol != (int)curwin->w_virtcol)
  1992.         {
  1993.             curwin->w_cursor.col = new_cursor_col;
  1994.             i = (int)curwin->w_virtcol - vcol;
  1995.             ptr = alloc(i + 1);
  1996.             if (ptr != NULL)
  1997.             {
  1998.                 new_cursor_col += i;
  1999.                 ptr[i] = NUL;
  2000.                 while (--i >= 0)
  2001.                     ptr[i] = ' ';
  2002.                 ins_str(ptr);
  2003.                 vim_free(ptr);
  2004.             }
  2005.         }
  2006.  
  2007.         /*
  2008.          * When changing the indent while the cursor is in it, reset
  2009.          * Insstart_col to 0.
  2010.          */
  2011.         insstart_less = Insstart.col;
  2012.     }
  2013.  
  2014.     curwin->w_p_list = save_p_list;
  2015.  
  2016.     if (new_cursor_col <= 0)
  2017.         curwin->w_cursor.col = 0;
  2018.     else
  2019.         curwin->w_cursor.col = new_cursor_col;
  2020.     curwin->w_set_curswant = TRUE;
  2021.  
  2022.     /*
  2023.      * May have to adjust the start of the insert.
  2024.      */
  2025.     if ((State & INSERT) && curwin->w_cursor.lnum == Insstart.lnum &&
  2026.                                                             Insstart.col != 0)
  2027.     {
  2028.         if ((int)Insstart.col <= insstart_less)
  2029.             Insstart.col = 0;
  2030.         else
  2031.             Insstart.col -= insstart_less;
  2032.     }
  2033. }
  2034.  
  2035. #ifdef INSERT_EXPAND
  2036. /*
  2037.  * Is the character 'c' a valid key to keep us in the current ctrl-x mode?
  2038.  * -- webb
  2039.  */
  2040.     int
  2041. is_ctrl_x_key(c)
  2042.     int        c;
  2043. {
  2044.     switch (ctrl_x_mode)
  2045.     {
  2046.         case 0:                /* Not in any ctrl-x mode */
  2047.             break;
  2048.         case CTRL_X_NOT_DEFINED_YET:
  2049.             if (c == Ctrl('X') || c == Ctrl('Y') || c == Ctrl('E') ||
  2050.                     c == Ctrl('L') || c == Ctrl('F') || c == Ctrl(']') ||
  2051.                     c == Ctrl('I') || c == Ctrl('D') || c == Ctrl('P') ||
  2052.                     c == Ctrl('N'))
  2053.                 return TRUE;
  2054.             break;
  2055.         case CTRL_X_SCROLL:
  2056.             if (c == Ctrl('Y') || c == Ctrl('E'))
  2057.                 return TRUE;
  2058.             break;
  2059.         case CTRL_X_WHOLE_LINE:
  2060.             if (c == Ctrl('L') || c == Ctrl('P') || c == Ctrl('N'))
  2061.                 return TRUE;
  2062.             break;
  2063.         case CTRL_X_FILES:
  2064.             if (c == Ctrl('F') || c == Ctrl('P') || c == Ctrl('N'))
  2065.                 return TRUE;
  2066.             break;
  2067.         case CTRL_X_DICTIONARY:
  2068.             if (c == Ctrl('K') || c == Ctrl('P') || c == Ctrl('N'))
  2069.                 return TRUE;
  2070.             break;
  2071.         case CTRL_X_TAGS:
  2072.             if (c == Ctrl(']') || c == Ctrl('P') || c == Ctrl('N'))
  2073.                 return TRUE;
  2074.             break;
  2075.         case CTRL_X_PATH_PATTERNS:
  2076.             if (c == Ctrl('P') || c == Ctrl('N'))
  2077.                 return TRUE;
  2078.             break;
  2079.         case CTRL_X_PATH_DEFINES:
  2080.             if (c == Ctrl('D') || c == Ctrl('P') || c == Ctrl('N'))
  2081.                 return TRUE;
  2082.             break;
  2083.         default:
  2084.             emsg(e_internal);
  2085.             break;
  2086.     }
  2087.     return FALSE;
  2088. }
  2089.  
  2090. /*
  2091.  * This is like add_completion(), but if ic and inf are set, then the
  2092.  * case of the originally typed text is used, and the case of the completed
  2093.  * text is infered, ie this tries to work out what case you probably wanted
  2094.  * the rest of the word to be in -- webb
  2095.  */
  2096.     int
  2097. add_completion_and_infercase(str, len, fname, dir)
  2098.     char_u    *str;
  2099.     int        len;
  2100.     char_u    *fname;
  2101.     int        dir;
  2102. {
  2103.     int has_lower = FALSE;
  2104.     int was_letter = FALSE;
  2105.     int orig_len;
  2106.     int idx;
  2107.  
  2108.     if (p_ic && curbuf->b_p_inf && len < IOSIZE)
  2109.     {
  2110.         /* Infer case of completed part -- webb */
  2111.         orig_len = STRLEN(original_text);
  2112.  
  2113.         /* Use IObuff, str would change text in buffer! */
  2114.         STRNCPY(IObuff, str, len);
  2115.         IObuff[len] = NUL;
  2116.  
  2117.         /* Rule 1: Were any chars converted to lower? */
  2118.         for (idx = 0; idx < orig_len; ++idx)
  2119.         {
  2120.             if (islower(original_text[idx]))
  2121.             {
  2122.                 has_lower = TRUE;
  2123.                 if (isupper(IObuff[idx]))
  2124.                 {
  2125.                     /* Rule 1 is satisfied */
  2126.                     for (idx = orig_len; idx < len; ++idx)
  2127.                         IObuff[idx] = TO_LOWER(IObuff[idx]);
  2128.                     break;
  2129.                 }
  2130.             }
  2131.         }
  2132.  
  2133.         /*
  2134.          * Rule 2: No lower case, 2nd consecutive letter converted to
  2135.          * upper case.
  2136.          */
  2137.         if (!has_lower)
  2138.         {
  2139.             for (idx = 0; idx < orig_len; ++idx)
  2140.             {
  2141.                 if (was_letter && isupper(original_text[idx]) &&
  2142.                     islower(IObuff[idx]))
  2143.                 {
  2144.                     /* Rule 2 is satisfied */
  2145.                     for (idx = orig_len; idx < len; ++idx)
  2146.                         IObuff[idx] = TO_UPPER(IObuff[idx]);
  2147.                     break;
  2148.                 }
  2149.                 was_letter = isalpha(original_text[idx]);
  2150.             }
  2151.         }
  2152.  
  2153.         /* Copy the original case of the part we typed */
  2154.         STRNCPY(IObuff, original_text, orig_len);
  2155.  
  2156.         return add_completion(IObuff, len, fname, dir);
  2157.     }
  2158.     return add_completion(str, len, fname, dir);
  2159. }
  2160.  
  2161. /*
  2162.  * Add a match to the list of matches.
  2163.  * If the given string is already in the list of completions, then return
  2164.  * FAIL, otherwise add it to the list and return OK.  If there is an error,
  2165.  * maybe because alloc returns NULL, then RET_ERROR is returned -- webb.
  2166.  */
  2167.     static int
  2168. add_completion(str, len, fname, dir)
  2169.     char_u    *str;
  2170.     int        len;
  2171.     char_u    *fname;
  2172.     int        dir;
  2173. {
  2174.     struct Completion *match;
  2175.  
  2176.     mch_breakcheck();
  2177.     if (got_int)
  2178.         return RET_ERROR;
  2179.     if (len < 0)
  2180.         len = STRLEN(str);
  2181.  
  2182.     /*
  2183.      * If the same match is already present, don't add it.
  2184.      */
  2185.     if (first_match != NULL)
  2186.     {
  2187.         match = first_match;
  2188.         do
  2189.         {
  2190.             if (STRNCMP(match->str, str, (size_t)len) == 0 &&
  2191.                                                        match->str[len] == NUL)
  2192.                 return FAIL;
  2193.             match = match->next;
  2194.         } while (match != NULL && match != first_match);
  2195.     }
  2196.  
  2197.     /*
  2198.      * Allocate a new match structure.
  2199.      * Copy the values to the new match structure.
  2200.      */
  2201.     match = (struct Completion *)alloc((unsigned)sizeof(struct Completion));
  2202.     if (match == NULL)
  2203.         return RET_ERROR;
  2204.     if ((match->str = strnsave(str, len)) == NULL)
  2205.     {
  2206.         vim_free(match);
  2207.         return RET_ERROR;
  2208.     }
  2209.     if (fname != NULL)
  2210.         match->fname = strsave(fname);        /* ignore errors */
  2211.     else
  2212.         match->fname = NULL;
  2213.     match->original = FALSE;
  2214.  
  2215.     /*
  2216.      * Link the new match structure in the list of matches.
  2217.      */
  2218.     if (first_match == NULL)
  2219.     {
  2220.         first_match = curr_match = match;
  2221.         curr_match->next = curr_match->prev = NULL;
  2222.     }
  2223.     else
  2224.     {
  2225.         if (dir == FORWARD)
  2226.         {
  2227.             match->next = NULL;
  2228.             match->prev = curr_match;
  2229.             curr_match->next = match;
  2230.             curr_match = match;
  2231.         }
  2232.         else    /* BACKWARD */
  2233.         {
  2234.             match->prev = NULL;
  2235.             match->next = curr_match;
  2236.             curr_match->prev = match;
  2237.             first_match = curr_match = match;
  2238.         }
  2239.     }
  2240.  
  2241.     return OK;
  2242. }
  2243.  
  2244. /*
  2245.  * Make the completion list cyclic.  Add the original text at the end.
  2246.  * Return the number of matches (excluding the original).
  2247.  */
  2248.     static int
  2249. make_cyclic()
  2250. {
  2251.     struct Completion *match, *orig;
  2252.     int        count = 0;
  2253.  
  2254.     if (first_match != NULL)
  2255.     {
  2256.         /*
  2257.          * Find the end of the list.
  2258.          */
  2259.         match = first_match;
  2260.         count = 1;
  2261.         while (match->next != NULL)
  2262.         {
  2263.             match = match->next;
  2264.             ++count;
  2265.         }
  2266.  
  2267.         if (original_text != NULL)
  2268.         {
  2269.             /*
  2270.              * Allocate a new structure for the original text.
  2271.              * Copy the original text to the new structure.
  2272.              * Link it in the list at the end.
  2273.              */
  2274.             orig = (struct Completion *)alloc((unsigned)sizeof(
  2275.                                                           struct Completion));
  2276.             if (orig != NULL)
  2277.             {
  2278.                 if ((orig->str = strsave(original_text)) == NULL)
  2279.                     vim_free(orig);
  2280.                 else
  2281.                 {
  2282.                     orig->fname = NULL;
  2283.                     orig->original = TRUE;
  2284.                     orig->prev = match;
  2285.                     match->next = orig;
  2286.                     match = orig;
  2287.                     curr_match = orig;
  2288.                 }
  2289.             }
  2290.         }
  2291.         match->next = first_match;
  2292.         first_match->prev = match;
  2293.     }
  2294.     return count;
  2295. }
  2296.  
  2297. /*
  2298.  * Add any identifiers that match the given pattern to the list of
  2299.  * completions.
  2300.  */
  2301.     static void
  2302. complete_dictionaries(pat, dir)
  2303.     char_u    *pat;
  2304.     int        dir;
  2305. {
  2306.     struct Completion *save_curr_match = curr_match;
  2307.     char_u    *dict = p_dict;
  2308.     char_u    *ptr;
  2309.     char_u    *buf;
  2310.     char_u    *fname;
  2311.     int        at_start;
  2312.     FILE    *fp;
  2313.     struct regexp *prog = NULL;
  2314.  
  2315.     if ((buf = alloc(LSIZE)) == NULL)
  2316.         return;
  2317.     if (curr_match != NULL)
  2318.     {
  2319.         while (curr_match->next != NULL)
  2320.             curr_match = curr_match->next;
  2321.     }
  2322.     if (*dict != NUL)
  2323.     {
  2324.         (void)set_highlight('r');
  2325.         msg_highlight = TRUE;
  2326.         MSG("Please wait, searching dictionaries");
  2327.         set_reg_ic(pat);    /* set reg_ic according to p_ic, p_scs and pat */
  2328.         reg_magic = p_magic;
  2329.         prog = vim_regcomp(pat);
  2330.     }
  2331.     while (*dict != NUL && prog != NULL && !got_int)
  2332.     {
  2333.                                 /* copy one dictionary file name into buf */
  2334.         (void)copy_option_part(&dict, buf, LSIZE, ",");
  2335.  
  2336.         fp = fopen((char *)buf, "r");        /* open dictionary file */
  2337.  
  2338.         if (fp != NULL)
  2339.         {
  2340.             fname = strsave(buf);            /* keep name of file */
  2341.             /*
  2342.              * Read dictionary file line by line.
  2343.              * Check each line for a match.
  2344.              */
  2345.             while (!got_int && !vim_fgets(buf, LSIZE, fp))
  2346.             {
  2347.                 ptr = buf;
  2348.                 at_start = TRUE;
  2349.                 while (vim_regexec(prog, ptr, at_start))
  2350.                 {
  2351.                     at_start = FALSE;
  2352.                     ptr = prog->startp[0];
  2353.                     while (iswordchar(*ptr))
  2354.                         ++ptr;
  2355.                     if (add_completion_and_infercase(prog->startp[0],
  2356.                                  (int)(ptr - prog->startp[0]), fname, FORWARD)
  2357.                                                                  == RET_ERROR)
  2358.                         break;
  2359.                 }
  2360.                 line_breakcheck();
  2361.             }
  2362.             fclose(fp);
  2363.             vim_free(fname);
  2364.         }
  2365.     }
  2366.     vim_free(prog);
  2367.     if (save_curr_match != NULL)
  2368.         curr_match = save_curr_match;
  2369.     else if (dir == BACKWARD)
  2370.         curr_match = first_match;
  2371.     vim_free(buf);
  2372. }
  2373.  
  2374. /*
  2375.  * Free the list of completions
  2376.  */
  2377.     static void
  2378. free_completions()
  2379. {
  2380.     struct Completion *match;
  2381.  
  2382.     if (first_match == NULL)
  2383.         return;
  2384.     curr_match = first_match;
  2385.     do
  2386.     {
  2387.         match = curr_match;
  2388.         curr_match = curr_match->next;
  2389.         vim_free(match->str);
  2390.         vim_free(match->fname);
  2391.         vim_free(match);
  2392.     } while (curr_match != NULL && curr_match != first_match);
  2393.     first_match = curr_match = NULL;
  2394. }
  2395.  
  2396. /*
  2397.  * Return the number of items in the Completion list
  2398.  */
  2399.     static int
  2400. count_completions()
  2401. {
  2402.     struct Completion *match;
  2403.     int num = 0;
  2404.  
  2405.     if (first_match == NULL)
  2406.         return 0;
  2407.     match = first_match;
  2408.     do
  2409.     {
  2410.         if (!match->original)        /* original string doesn't count */
  2411.             num++;
  2412.         match = match->next;
  2413.     } while (match != NULL && match != first_match);
  2414.     return num;
  2415. }
  2416. #endif /* INSERT_EXPAND */
  2417.  
  2418. /*
  2419.  * Next character is interpreted literally.
  2420.  * A one, two or three digit decimal number is interpreted as its byte value.
  2421.  * If one or two digits are entered, the next character is given to vungetc().
  2422.  */
  2423.     int
  2424. get_literal()
  2425. {
  2426.     int             cc;
  2427.     int             nc;
  2428.     int             i;
  2429.  
  2430.     if (got_int)
  2431.         return Ctrl('C');
  2432.  
  2433. #ifdef USE_GUI
  2434.     /*
  2435.      * In GUI there is no point inserting the internal code for a special key.
  2436.      * It is more useful to insert the string "<KEY>" instead.  This would
  2437.      * probably be useful in a text window too, but it would not be
  2438.      * vi-compatible (maybe there should be an option for it?) -- webb
  2439.      */
  2440.     if (gui.in_use)
  2441.         ++allow_keys;
  2442. #endif
  2443.     ++no_mapping;            /* don't map the next key hits */
  2444.     cc = 0;
  2445.     for (i = 0; i < 3; ++i)
  2446.     {
  2447.         do
  2448.             nc = vgetc();
  2449.         while (nc == K_IGNORE || nc == K_SCROLLBAR || nc == K_HORIZ_SCROLLBAR);
  2450.         if (!(State & CMDLINE))
  2451.             add_to_showcmd(nc, FALSE);
  2452.         if (IS_SPECIAL(nc) || !isdigit(nc))
  2453.             break;
  2454.         cc = cc * 10 + nc - '0';
  2455.         if (cc > 255)
  2456.             cc = 255;            /* limit range to 0-255 */
  2457.         nc = 0;
  2458.     }
  2459.     if (i == 0)        /* no number entered */
  2460.     {
  2461.         if (nc == K_ZERO)    /* NUL is stored as NL */
  2462.         {
  2463.             cc = '\n';
  2464.             nc = 0;
  2465.         }
  2466.         else
  2467.         {
  2468.             cc = nc;
  2469.             nc = 0;
  2470.         }
  2471.     }
  2472.  
  2473.     if (cc == 0)        /* NUL is stored as NL */
  2474.         cc = '\n';
  2475.  
  2476.     --no_mapping;
  2477. #ifdef USE_GUI
  2478.     if (gui.in_use)
  2479.         --allow_keys;
  2480. #endif
  2481.     if (nc)
  2482.         vungetc(nc);
  2483.     got_int = FALSE;        /* CTRL-C typed after CTRL-V is not an interrupt */
  2484.     return cc;
  2485. }
  2486.  
  2487. /*
  2488.  * Insert character, taking care of special keys and mod_mask
  2489.  */
  2490.     static void
  2491. insert_special(c, allow_modmask)
  2492.     int        c;
  2493.     int        allow_modmask;
  2494. {
  2495.     char_u    *p;
  2496.     int        len;
  2497.  
  2498.     /*
  2499.      * Special function key, translate into "<Key>". Up to the last '>' is
  2500.      * inserted with ins_str(), so as not to replace characters in replace
  2501.      * mode.
  2502.      * Only use mod_mask for special keys, to avoid things like <S-Space>,
  2503.      * unless 'allow_modmask' is TRUE.
  2504.      */
  2505.     if (IS_SPECIAL(c) || (mod_mask && allow_modmask))
  2506.     {
  2507.         p = get_special_key_name(c, mod_mask);
  2508.         len = STRLEN(p);
  2509.         c = p[len - 1];
  2510.         if (len > 2)
  2511.         {
  2512.             p[len - 1] = NUL;
  2513.             ins_str(p);
  2514.             AppendToRedobuff(p);
  2515.         }
  2516.     }
  2517.     insertchar(c, FALSE, -1);
  2518. }
  2519.  
  2520. /*
  2521.  * Special characters in this context are those that need processing other
  2522.  * than the simple insertion that can be performed here. This includes ESC
  2523.  * which terminates the insert, and CR/NL which need special processing to
  2524.  * open up a new line. This routine tries to optimize insertions performed by
  2525.  * the "redo", "undo" or "put" commands, so it needs to know when it should
  2526.  * stop and defer processing to the "normal" mechanism.
  2527.  */
  2528. #define ISSPECIAL(c)    ((c) < ' ' || (c) >= DEL)
  2529.  
  2530.     void
  2531. insertchar(c, force_formatting, second_indent)
  2532.     unsigned    c;
  2533.     int            force_formatting;        /* format line regardless of p_fo */
  2534.     int            second_indent;            /* indent for second line if >= 0 */
  2535. {
  2536.     int            haveto_redraw = FALSE;
  2537.     int            textwidth;
  2538.     colnr_t        leader_len;
  2539.     int            first_line = TRUE;
  2540.     int            fo_ins_blank;
  2541.     int            save_char = NUL;
  2542.  
  2543.     stop_arrow();
  2544.  
  2545.     /*
  2546.      * find out textwidth to be used:
  2547.      *    if 'textwidth' option is set, use it
  2548.      *    else if 'wrapmargin' option is set, use Columns - 'wrapmargin'
  2549.      *    if invalid value, use 0.
  2550.      *  Set default to window width (maximum 79) for "Q" command.
  2551.      */
  2552.     textwidth = curbuf->b_p_tw;
  2553.     if (textwidth == 0 && curbuf->b_p_wm)
  2554.         textwidth = Columns - curbuf->b_p_wm;
  2555.     if (textwidth < 0)
  2556.         textwidth = 0;
  2557.     if (force_formatting && textwidth == 0)
  2558.     {
  2559.         textwidth = Columns - 1;
  2560.         if (textwidth > 79)
  2561.             textwidth = 79;
  2562.     }
  2563.  
  2564.     fo_ins_blank = has_format_option(FO_INS_BLANK);
  2565.  
  2566.     /*
  2567.      * Try to break the line in two or more pieces when:
  2568.      * - Always do this if we have been called to do formatting only.
  2569.      * - Otherwise:
  2570.      *   - Don't do this if inserting a blank
  2571.      *   - Don't do this if an existing character is being replaced.
  2572.      *   - Do this if the cursor is not on the line where insert started
  2573.      *   or - 'formatoptions' doesn't have 'l' or the line was not too long
  2574.      *         before the insert.
  2575.      *      - 'formatoptions' doesn't have 'b' or a blank was inserted at or
  2576.      *        before 'textwidth'
  2577.      */
  2578.     if (force_formatting || (!vim_iswhite(c) &&
  2579.                              !(State == REPLACE && *ml_get_cursor() != NUL) &&
  2580.                                     (curwin->w_cursor.lnum != Insstart.lnum ||
  2581.                                           ((!has_format_option(FO_INS_LONG) ||
  2582.                                     Insstart_textlen <= (colnr_t)textwidth) &&
  2583.               (!fo_ins_blank || Insstart_blank_vcol <= (colnr_t)textwidth)))))
  2584.     {
  2585.         /*
  2586.          * When 'ai' is off we don't want a space under the cursor to be
  2587.          * deleted.  Replace it with an 'x' temporarily.
  2588.          */
  2589.         if (!curbuf->b_p_ai && vim_iswhite(gchar_cursor()))
  2590.         {
  2591.             save_char = gchar_cursor();
  2592.             pchar_cursor('x');
  2593.         }
  2594.         while (textwidth && curwin->w_virtcol >= (colnr_t)textwidth)
  2595.         {
  2596.             int        startcol;            /* Cursor column at entry */
  2597.             int        wantcol;            /* column at textwidth border */
  2598.             int        foundcol;            /* column for start of spaces */
  2599.             int        end_foundcol = 0;    /* column for start of word */
  2600.             colnr_t    len;
  2601.  
  2602.             if (!force_formatting && has_format_option(FO_WRAP_COMS))
  2603.                 fo_do_comments = TRUE;
  2604.  
  2605.             /* Don't break until after the comment leader */
  2606.             leader_len = get_leader_len(ml_get_curline(), NULL);
  2607.             if (!force_formatting && leader_len == 0 &&
  2608.                                                   !has_format_option(FO_WRAP))
  2609.  
  2610.             {
  2611.                 textwidth = 0;
  2612.                 break;
  2613.             }
  2614.             if ((startcol = curwin->w_cursor.col) == 0)
  2615.                 break;
  2616.                                         /* find column of textwidth border */
  2617.             coladvance((colnr_t)textwidth);
  2618.             wantcol = curwin->w_cursor.col;
  2619.  
  2620.             curwin->w_cursor.col = startcol - 1;
  2621.             foundcol = 0;
  2622.             /*
  2623.              * Find position to break at.
  2624.              * Stop at start of line.
  2625.              * Stop at first entered white when 'formatoptions' has 'v'
  2626.              */
  2627.             while (curwin->w_cursor.col > 0 &&
  2628.                           ((!fo_ins_blank && !has_format_option(FO_INS_VI)) ||
  2629.                                  curwin->w_cursor.lnum != Insstart.lnum ||
  2630.                                      curwin->w_cursor.col >= Insstart.col))
  2631.             {
  2632.                 if (vim_iswhite(gchar_cursor()))
  2633.                 {
  2634.                         /* remember position of blank just before text */
  2635.                     end_foundcol = curwin->w_cursor.col;
  2636.                     while (curwin->w_cursor.col > 0 &&
  2637.                                                   vim_iswhite(gchar_cursor()))
  2638.                         --curwin->w_cursor.col;
  2639.                     if (curwin->w_cursor.col == 0 &&
  2640.                                                   vim_iswhite(gchar_cursor()))
  2641.                         break;            /* only spaces in front of text */
  2642.                     /* Don't break until after the comment leader */
  2643.                     if (curwin->w_cursor.col < leader_len)
  2644.                         break;
  2645.                     foundcol = curwin->w_cursor.col + 1;
  2646.                     if (curwin->w_cursor.col < (colnr_t)wantcol)
  2647.                         break;
  2648.                 }
  2649.                 --curwin->w_cursor.col;
  2650.             }
  2651.  
  2652.             if (foundcol == 0)            /* no spaces, cannot break line */
  2653.             {
  2654.                 curwin->w_cursor.col = startcol;
  2655.                 break;
  2656.             }
  2657.  
  2658.             /*
  2659.              * offset between cursor position and line break is used by
  2660.              * replace stack functions
  2661.              */
  2662.             replace_offset = startcol - end_foundcol - 1;
  2663.  
  2664.             /*
  2665.              * adjust startcol for spaces that will be deleted and
  2666.              * characters that will remain on top line
  2667.              */
  2668.             curwin->w_cursor.col = foundcol;
  2669.             while (vim_iswhite(gchar_cursor()))
  2670.             {
  2671.                 ++curwin->w_cursor.col;
  2672.                 --startcol;
  2673.             }
  2674.             startcol -= foundcol;
  2675.             if (startcol < 0)
  2676.                 startcol = 0;
  2677.  
  2678.                 /* put cursor after pos. to break line */
  2679.             curwin->w_cursor.col = foundcol;
  2680.  
  2681.             Opencmd(FORWARD, FALSE, TRUE);
  2682.  
  2683.             replace_offset = 0;
  2684.             if (second_indent >= 0 && first_line)
  2685.                 set_indent(second_indent, TRUE);
  2686.             first_line = FALSE;
  2687.  
  2688.             /*
  2689.              * check if cursor is not past the NUL off the line, cindent may
  2690.              * have added or removed indent.
  2691.              */
  2692.             curwin->w_cursor.col += startcol;
  2693.             len = STRLEN(ml_get_curline());
  2694.             if (curwin->w_cursor.col > len)
  2695.                 curwin->w_cursor.col = len;
  2696.  
  2697.             curs_columns(FALSE);        /* update curwin->w_virtcol */
  2698.             haveto_redraw = TRUE;
  2699. #ifdef CINDENT
  2700.             can_cindent = TRUE;
  2701. #endif
  2702.         }
  2703.  
  2704.         if (save_char)                    /* put back space after cursor */
  2705.             pchar_cursor(save_char);
  2706.  
  2707.         if (c == NUL)                    /* formatting only */
  2708.             return;
  2709.         fo_do_comments = FALSE;
  2710.         if (haveto_redraw)
  2711.         {
  2712.             /*
  2713.              * If the cursor ended up just below the screen we scroll up here
  2714.              * to avoid a redraw of the whole screen in the most common cases.
  2715.              */
  2716.              if (curwin->w_cursor.lnum == curwin->w_botline &&
  2717.                                                         !curwin->w_empty_rows)
  2718.                 win_del_lines(curwin, 0, 1, TRUE, TRUE);
  2719.             updateScreen(CURSUPD);
  2720.         }
  2721.     }
  2722.     if (c == NUL)            /* only formatting was wanted */
  2723.         return;
  2724.  
  2725.     did_ai = FALSE;
  2726.     did_si = FALSE;
  2727.     can_si = FALSE;
  2728.     can_si_back = FALSE;
  2729.  
  2730.     /*
  2731.      * If there's any pending input, grab up to INPUT_BUFLEN at once.
  2732.      * This speeds up normal text input considerably.
  2733.      */
  2734. #define INPUT_BUFLEN 100
  2735.     if (!ISSPECIAL(c) && vpeekc() != NUL && State != REPLACE
  2736. #ifdef RIGHTLEFT
  2737.                                                                 && !p_ri
  2738. #endif
  2739.                                                                         )
  2740.     {
  2741.         char_u            p[INPUT_BUFLEN + 1];
  2742.         int             i;
  2743.  
  2744.         p[0] = c;
  2745.         i = 1;
  2746.         while ((c = vpeekc()) != NUL && !ISSPECIAL(c) && i < INPUT_BUFLEN &&
  2747.                                                             (textwidth == 0 ||
  2748.             (curwin->w_virtcol += charsize(p[i - 1])) < (colnr_t)textwidth) &&
  2749.                     !(!no_abbr && !iswordchar(c) && iswordchar(p[i - 1])))
  2750.         {
  2751. #ifdef RIGHTLEFT
  2752.             c = vgetc();
  2753.             if (p_hkmap && KeyTyped)
  2754.                 c = hkmap(c);                /* Hebrew mode mapping */
  2755.             p[i++] = c;
  2756. #else
  2757.              p[i++] = vgetc();
  2758. #endif
  2759.         }
  2760.             
  2761. #ifdef DIGRAPHS
  2762.         do_digraph(-1);                    /* clear digraphs */
  2763.         do_digraph(p[i-1]);                /* may be the start of a digraph */
  2764. #endif
  2765.         p[i] = '\0';
  2766.         ins_str(p);
  2767.         AppendToRedobuff(p);
  2768.     }
  2769.     else
  2770.     {
  2771.         ins_char(c);
  2772.         AppendCharToRedobuff(c);
  2773.     }
  2774. }
  2775.  
  2776. /*
  2777.  * start_arrow() is called when an arrow key is used in insert mode.
  2778.  * It resembles hitting the <ESC> key.
  2779.  */
  2780.     static void
  2781. start_arrow(end_insert_pos)
  2782.     FPOS    *end_insert_pos;
  2783. {
  2784.     if (!arrow_used)        /* something has been inserted */
  2785.     {
  2786.         AppendToRedobuff(ESC_STR);
  2787.         arrow_used = TRUE;        /* this means we stopped the current insert */
  2788.         stop_insert(end_insert_pos);
  2789.     }
  2790. }
  2791.  
  2792. /*
  2793.  * stop_arrow() is called before a change is made in insert mode.
  2794.  * If an arrow key has been used, start a new insertion.
  2795.  */
  2796.     static void
  2797. stop_arrow()
  2798. {
  2799.     if (arrow_used)
  2800.     {
  2801.         (void)u_save_cursor();                /* errors are ignored! */
  2802.         Insstart = curwin->w_cursor;    /* new insertion starts here */
  2803.         Insstart_textlen = linetabsize(ml_get_curline());
  2804.         ResetRedobuff();
  2805.         AppendToRedobuff((char_u *)"1i");    /* pretend we start an insertion */
  2806.         arrow_used = FALSE;
  2807.     }
  2808. }
  2809.  
  2810. /*
  2811.  * do a few things to stop inserting
  2812.  */
  2813.     static void
  2814. stop_insert(end_insert_pos)
  2815.     FPOS    *end_insert_pos;        /* where insert ended */
  2816. {
  2817.     stop_redo_ins();
  2818.  
  2819.     /*
  2820.      * save the inserted text for later redo with ^@
  2821.      */
  2822.     vim_free(last_insert);
  2823.     last_insert = get_inserted();
  2824.     last_insert_skip = new_insert_skip;
  2825.  
  2826.     /*
  2827.      * If we just did an auto-indent, remove the white space from the end of
  2828.      * the line, and put the cursor back.
  2829.      */
  2830.     if (did_ai && !arrow_used)
  2831.     {
  2832.         if (gchar_cursor() == NUL && curwin->w_cursor.col > 0)
  2833.             --curwin->w_cursor.col;
  2834.         while (vim_iswhite(gchar_cursor()))
  2835.             delchar(TRUE);
  2836.         if (gchar_cursor() != NUL)
  2837.             ++curwin->w_cursor.col;        /* put cursor back on the NUL */
  2838.         if (curwin->w_p_list)            /* the deletion is only seen in list
  2839.                                          * mode */
  2840.             updateline();
  2841.     }
  2842.     did_ai = FALSE;
  2843.     did_si = FALSE;
  2844.     can_si = FALSE;
  2845.     can_si_back = FALSE;
  2846.  
  2847.     /* set '[ and '] to the inserted text */
  2848.     curbuf->b_op_start = Insstart;
  2849.     curbuf->b_op_end = *end_insert_pos;
  2850. }
  2851.  
  2852. /*
  2853.  * Set the last inserted text to a single character.
  2854.  * Used for the replace command.
  2855.  */
  2856.     void
  2857. set_last_insert(c)
  2858.     int        c;
  2859. {
  2860.     vim_free(last_insert);
  2861.     last_insert = alloc(4);
  2862.     if (last_insert != NULL)
  2863.     {
  2864.         last_insert[0] = Ctrl('V');
  2865.         last_insert[1] = c;
  2866.         last_insert[2] = ESC;
  2867.         last_insert[3] = NUL;
  2868.             /* Use the CTRL-V only when not entering a digit */
  2869.         last_insert_skip = isdigit(c) ? 1 : 0;
  2870.     }
  2871. }
  2872.  
  2873. /*
  2874.  * move cursor to start of line
  2875.  * if flag == TRUE move to first non-white
  2876.  * if flag == MAYBE then move to first non-white if startofline is set,
  2877.  *        otherwise don't move at all.
  2878.  */
  2879.     void
  2880. beginline(flag)
  2881.     int            flag;
  2882. {
  2883.     if (flag == MAYBE && !p_sol)
  2884.         coladvance(curwin->w_curswant);
  2885.     else
  2886.     {
  2887.         curwin->w_cursor.col = 0;
  2888.         if (flag)
  2889.         {
  2890.             register char_u *ptr;
  2891.  
  2892.             for (ptr = ml_get_curline(); vim_iswhite(*ptr); ++ptr)
  2893.                 ++curwin->w_cursor.col;
  2894.         }
  2895.         curwin->w_set_curswant = TRUE;
  2896.     }
  2897. }
  2898.  
  2899. /*
  2900.  * oneright oneleft cursor_down cursor_up
  2901.  *
  2902.  * Move one char {right,left,down,up}.
  2903.  * Return OK when sucessful, FAIL when we hit a line of file boundary.
  2904.  */
  2905.  
  2906.     int
  2907. oneright()
  2908. {
  2909.     char_u *ptr;
  2910.  
  2911.     ptr = ml_get_cursor();
  2912.     if (*ptr++ == NUL || *ptr == NUL)
  2913.         return FAIL;
  2914.     curwin->w_set_curswant = TRUE;
  2915.     ++curwin->w_cursor.col;
  2916.     return OK;
  2917. }
  2918.  
  2919.     int
  2920. oneleft()
  2921. {
  2922.     if (curwin->w_cursor.col == 0)
  2923.         return FAIL;
  2924.     curwin->w_set_curswant = TRUE;
  2925.     --curwin->w_cursor.col;
  2926.     return OK;
  2927. }
  2928.  
  2929.     int
  2930. cursor_up(n)
  2931.     long n;
  2932. {
  2933.     if (n != 0 && curwin->w_cursor.lnum == 1)
  2934.         return FAIL;
  2935.     if (n >= curwin->w_cursor.lnum)
  2936.         curwin->w_cursor.lnum = 1;
  2937.     else
  2938.         curwin->w_cursor.lnum -= n;
  2939.  
  2940.     /* try to advance to the column we want to be at */
  2941.     coladvance(curwin->w_curswant);
  2942.  
  2943.     if (op_type == NOP)
  2944.         cursupdate();                /* make sure curwin->w_topline is valid */
  2945.  
  2946.     return OK;
  2947. }
  2948.  
  2949.     int
  2950. cursor_down(n)
  2951.     long n;
  2952. {
  2953.     if (n != 0 && curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count)
  2954.         return FAIL;
  2955.     curwin->w_cursor.lnum += n;
  2956.     if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
  2957.         curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  2958.  
  2959.     /* try to advance to the column we want to be at */
  2960.     coladvance(curwin->w_curswant);
  2961.  
  2962.     if (op_type == NOP)
  2963.         cursupdate();                /* make sure curwin->w_topline is valid */
  2964.  
  2965.     return OK;
  2966. }
  2967.  
  2968. /*
  2969.  * screengo() --
  2970.  *
  2971.  * move 'dist' lines in direction 'dir', counting lines by *screen*
  2972.  * lines rather than lines in the file
  2973.  * 'dist' must be positive.
  2974.  *
  2975.  * return OK if able to move cursor, FAIL otherwise.
  2976.  */
  2977.  
  2978.     int
  2979. screengo(dir, dist)
  2980.     int        dir;
  2981.     long    dist;
  2982. {
  2983.     int        linelen = linetabsize(ml_get_curline());
  2984.     int        retval = OK;
  2985.     int        atend = FALSE;
  2986.     int        n;
  2987.  
  2988.     op_motion_type = MCHAR;
  2989.     op_inclusive = FALSE;
  2990.  
  2991.     /*
  2992.      * Instead of sticking at the last character of the line in the file we
  2993.      * try to stick in the last column of the screen
  2994.      */
  2995.     if (curwin->w_curswant == MAXCOL)
  2996.     {
  2997.         atend = TRUE;
  2998.         curwin->w_curswant = ((curwin->w_virtcol +
  2999.                        (curwin->w_p_nu ? 8 : 0)) / Columns + 1) * Columns - 1;
  3000.         if (curwin->w_p_nu && curwin->w_curswant > 8)
  3001.             curwin->w_curswant -= 8;
  3002.     }
  3003.     else
  3004.         while (curwin->w_curswant >= (colnr_t)(linelen + Columns))
  3005.             curwin->w_curswant -= Columns;
  3006.  
  3007.     while (dist--)
  3008.     {
  3009.         if (dir == BACKWARD)
  3010.         {
  3011.                                                 /* move back within line */
  3012.             if ((long)curwin->w_curswant >= Columns)
  3013.                 curwin->w_curswant -= Columns;
  3014.             else                                /* to previous line */
  3015.             {
  3016.                 if (curwin->w_cursor.lnum == 1)
  3017.                 {
  3018.                     retval = FAIL;
  3019.                     break;
  3020.                 }
  3021.                 --curwin->w_cursor.lnum;
  3022.                 linelen = linetabsize(ml_get_curline());
  3023.                 n = ((linelen + (curwin->w_p_nu ? 8 : 0) - 1) / Columns)
  3024.                                                                     * Columns;
  3025.                 if (curwin->w_p_nu &&
  3026.                                  (long)curwin->w_curswant >= Columns - 8 && n)
  3027.                     n -= Columns;
  3028.                 curwin->w_curswant += n;
  3029.             }
  3030.         }
  3031.         else /* dir == FORWARD */
  3032.         {
  3033.             n = ((linelen + (curwin->w_p_nu ? 8 : 0) - 1) / Columns) * Columns;
  3034.             if (curwin->w_p_nu && n > 8)
  3035.                 n -= 8;
  3036.                                                 /* move forward within line */
  3037.             if (curwin->w_curswant < (colnr_t)n)
  3038.                 curwin->w_curswant += Columns;
  3039.             else                                /* to next line */
  3040.             {
  3041.                 if (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count)
  3042.                 {
  3043.                     retval = FAIL;
  3044.                     break;
  3045.                 }
  3046.                 curwin->w_cursor.lnum++;
  3047.                 linelen = linetabsize(ml_get_curline());
  3048.                 curwin->w_curswant %= Columns;
  3049.             }
  3050.         }
  3051.     }
  3052.     coladvance(curwin->w_curswant);
  3053.     if (atend)
  3054.         curwin->w_curswant = MAXCOL;        /* stick in the last column */
  3055.     if (op_type == NOP)
  3056.         cursupdate();
  3057.     return retval;
  3058. }
  3059.  
  3060. /*
  3061.  * move screen 'count' pages up or down and update screen
  3062.  *
  3063.  * return FAIL for failure, OK otherwise
  3064.  */
  3065.     int
  3066. onepage(dir, count)
  3067.     int        dir;
  3068.     long    count;
  3069. {
  3070.     linenr_t        lp;
  3071.     long            n;
  3072.     int                off;
  3073.  
  3074.     if (curbuf->b_ml.ml_line_count == 1)    /* nothing to do */
  3075.         return FAIL;
  3076.     for ( ; count > 0; --count)
  3077.     {
  3078.         if (dir == FORWARD ? (curwin->w_topline >=
  3079.                    curbuf->b_ml.ml_line_count - 1) : (curwin->w_topline == 1))
  3080.         {
  3081.             beep_flush();
  3082.             return FAIL;
  3083.         }
  3084.         if (dir == FORWARD)
  3085.         {
  3086.                                         /* at end of file */
  3087.             if (curwin->w_botline > curbuf->b_ml.ml_line_count)
  3088.                 curwin->w_topline = curbuf->b_ml.ml_line_count;
  3089.                                         /* next line is big */
  3090.                                         /* or just three lines on screen */
  3091.             else
  3092.             {
  3093.                 if (plines(curwin->w_botline) >= curwin->w_height - 2 ||
  3094.                                    curwin->w_botline - curwin->w_topline <= 3)
  3095.                     off = 0;
  3096.                 else
  3097.                     off = 2;
  3098.                 curwin->w_topline = curwin->w_botline - off;
  3099.                 curwin->w_cursor.lnum = curwin->w_topline;
  3100.             }
  3101.             comp_Botline(curwin);
  3102.         }
  3103.         else    /* dir == BACKWARDS */
  3104.         {
  3105.             lp = curwin->w_topline;
  3106.             /*
  3107.              * If the first two lines on the screen are not too big, we keep
  3108.              * them on the screen.
  3109.              */
  3110.             if ((n = plines(lp)) > curwin->w_height / 2)
  3111.                 --lp;
  3112.             else if (lp < curbuf->b_ml.ml_line_count &&
  3113.                                     n + plines(lp + 1) < curwin->w_height / 2)
  3114.                 ++lp;
  3115.             curwin->w_cursor.lnum = lp;
  3116.             n = 0;
  3117.             while (n <= curwin->w_height && lp >= 1)
  3118.             {
  3119.                 n += plines(lp);
  3120.                 --lp;
  3121.             }
  3122.             if (n <= curwin->w_height)                /* at begin of file */
  3123.             {
  3124.                 curwin->w_topline = 1;
  3125.                 comp_Botline(curwin);
  3126.             }
  3127.             else if (lp >= curwin->w_topline - 2)    /* very long lines */
  3128.             {
  3129.                 --curwin->w_topline;
  3130.                 comp_Botline(curwin);
  3131.                 curwin->w_cursor.lnum = curwin->w_botline - 1;
  3132.             }
  3133.             else
  3134.             {
  3135.                 curwin->w_topline = lp + 2;
  3136.                 comp_Botline(curwin);
  3137.             }
  3138.         }
  3139.     }
  3140.     cursor_correct();
  3141.     beginline(MAYBE);
  3142.     updateScreen(VALID);
  3143.     return OK;
  3144. }
  3145.  
  3146. /* #define KEEP_SCREEN_LINE */
  3147.  
  3148.     void
  3149. halfpage(flag, Prenum)
  3150.     int            flag;
  3151.     linenr_t    Prenum;
  3152. {
  3153.     long        scrolled = 0;
  3154.     int            i;
  3155.     int            n;
  3156.  
  3157.     if (Prenum)
  3158.         curwin->w_p_scroll = (Prenum > curwin->w_height) ?
  3159.                                                 curwin->w_height : Prenum;
  3160.     n = (curwin->w_p_scroll <= curwin->w_height) ?
  3161.                                     curwin->w_p_scroll : curwin->w_height;
  3162.  
  3163.     if (flag)        /* scroll down */
  3164.     {
  3165.         while (n > 0 && curwin->w_botline <= curbuf->b_ml.ml_line_count)
  3166.         {
  3167.             i = plines(curwin->w_topline);
  3168.             n -= i;
  3169.             if (n < 0 && scrolled)
  3170.                 break;
  3171.             scrolled += i;
  3172.             ++curwin->w_topline;
  3173.             comp_Botline(curwin);        /* compute curwin->w_botline */
  3174. #ifndef KEEP_SCREEN_LINE
  3175.             if (curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
  3176.                 ++curwin->w_cursor.lnum;
  3177. #endif
  3178.         }
  3179. #ifndef KEEP_SCREEN_LINE
  3180.         /*
  3181.          * When hit bottom of the file: move cursor down.
  3182.          */
  3183.         if (n > 0)
  3184.         {
  3185.             curwin->w_cursor.lnum += n;
  3186.             if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
  3187.                 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  3188.         }
  3189. #else
  3190.             /* try to put the cursor in the same screen line */
  3191.         while ((curwin->w_cursor.lnum < curwin->w_topline || scrolled > 0)
  3192.                              && curwin->w_cursor.lnum < curwin->w_botline - 1)
  3193.         {
  3194.             scrolled -= plines(curwin->w_cursor.lnum);
  3195.             if (scrolled < 0 && curwin->w_cursor.lnum >= curwin->w_topline)
  3196.                 break;
  3197.             ++curwin->w_cursor.lnum;
  3198.         }
  3199. #endif
  3200.     }
  3201.     else            /* scroll up */
  3202.     {
  3203.         while (n > 0 && curwin->w_topline > 1)
  3204.         {
  3205.             i = plines(curwin->w_topline - 1);
  3206.             n -= i;
  3207.             if (n < 0 && scrolled)
  3208.                 break;
  3209.             scrolled += i;
  3210.             --curwin->w_topline;
  3211. #ifndef KEEP_SCREEN_LINE
  3212.             if (curwin->w_cursor.lnum > 1)
  3213.                 --curwin->w_cursor.lnum;
  3214. #endif
  3215.         }
  3216.         comp_Botline(curwin);        /* compute curwin->w_botline */
  3217. #ifndef KEEP_SCREEN_LINE
  3218.         /*
  3219.          * When hit top of the file: move cursor up.
  3220.          */
  3221.         if (n > 0)
  3222.         {
  3223.             if (curwin->w_cursor.lnum > (linenr_t)n)
  3224.                 curwin->w_cursor.lnum -= n;
  3225.             else
  3226.                 curwin->w_cursor.lnum = 1;
  3227.         }
  3228. #else
  3229.             /* try to put the cursor in the same screen line */
  3230.         scrolled += n;        /* move cursor when topline is 1 */
  3231.         while (curwin->w_cursor.lnum > curwin->w_topline &&
  3232.                  (scrolled > 0 || curwin->w_cursor.lnum >= curwin->w_botline))
  3233.         {
  3234.             scrolled -= plines(curwin->w_cursor.lnum - 1);
  3235.             if (scrolled < 0 && curwin->w_cursor.lnum < curwin->w_botline)
  3236.                 break;
  3237.             --curwin->w_cursor.lnum;
  3238.         }
  3239. #endif
  3240.     }
  3241.     cursor_correct();
  3242.     beginline(MAYBE);
  3243.     updateScreen(VALID);
  3244. }
  3245.  
  3246. /*
  3247.  * Stuff the last inserted text in the read buffer.
  3248.  * Last_insert actually is a copy of the redo buffer, so we
  3249.  * first have to remove the command.
  3250.  */
  3251.     int
  3252. stuff_inserted(c, count, no_esc)
  3253.     int        c;
  3254.     long    count;
  3255.     int        no_esc;
  3256. {
  3257.     char_u        *esc_ptr = NULL;
  3258.     char_u        *ptr;
  3259.  
  3260.     ptr = get_last_insert();
  3261.     if (ptr == NULL)
  3262.     {
  3263.         EMSG(e_noinstext);
  3264.         return FAIL;
  3265.     }
  3266.  
  3267.     if (c)
  3268.         stuffcharReadbuff(c);
  3269.     if (no_esc && (esc_ptr = (char_u *)vim_strrchr(ptr, 27)) != NULL)
  3270.         *esc_ptr = NUL;        /* remove the ESC */
  3271.  
  3272.     do
  3273.         stuffReadbuff(ptr);
  3274.     while (--count > 0);
  3275.  
  3276.     if (esc_ptr != NULL)
  3277.         *esc_ptr = 27;        /* put the ESC back */
  3278.  
  3279.     return OK;
  3280. }
  3281.  
  3282.     char_u *
  3283. get_last_insert()
  3284. {
  3285.     if (last_insert == NULL)
  3286.         return NULL;
  3287.     return last_insert + last_insert_skip;
  3288. }
  3289.  
  3290. /*
  3291.  * Check the word in front of the cursor for an abbreviation.
  3292.  * Called when the non-id character "c" has been entered.
  3293.  * When an abbreviation is recognized it is removed from the text and
  3294.  * the replacement string is inserted in typebuf[], followed by "c".
  3295.  */
  3296.     static int
  3297. echeck_abbr(c)
  3298.     int c;
  3299. {
  3300.     if (p_paste || no_abbr)            /* no abbreviations or in paste mode */
  3301.         return FALSE;
  3302.  
  3303.     return check_abbr(c, ml_get_curline(), curwin->w_cursor.col,
  3304.                 curwin->w_cursor.lnum == Insstart.lnum ? Insstart.col : 0);
  3305. }
  3306.  
  3307. /*
  3308.  * replace-stack functions
  3309.  *
  3310.  * When replacing characters the replaced character is remembered
  3311.  * for each new character. This is used to re-insert the old text
  3312.  * when backspacing.
  3313.  *
  3314.  * replace_offset is normally 0, in which case replace_push will add a new
  3315.  * character at the end of the stack. If replace_offset is not 0, that many
  3316.  * characters will be left on the stack above the newly inserted character.
  3317.  */
  3318.  
  3319. char_u    *replace_stack = NULL;
  3320. long    replace_stack_nr = 0;        /* next entry in replace stack */
  3321. long    replace_stack_len = 0;        /* max. number of entries */
  3322.  
  3323.     void
  3324. replace_push(c)
  3325.     int        c;        /* character that is replaced (NUL is none) */
  3326. {
  3327.     char_u    *p;
  3328.  
  3329.     if (replace_stack_nr < replace_offset)        /* nothing to do */
  3330.         return;
  3331.     if (replace_stack_len <= replace_stack_nr)
  3332.     {
  3333.         replace_stack_len += 50;
  3334.         p = lalloc(sizeof(char_u) * replace_stack_len, TRUE);
  3335.         if (p == NULL)        /* out of memory */
  3336.         {
  3337.             replace_stack_len -= 50;
  3338.             return;
  3339.         }
  3340.         if (replace_stack != NULL)
  3341.         {
  3342.             vim_memmove(p, replace_stack,
  3343.                                  (size_t)(replace_stack_nr * sizeof(char_u)));
  3344.             vim_free(replace_stack);
  3345.         }
  3346.         replace_stack = p;
  3347.     }
  3348.     p = replace_stack + replace_stack_nr - replace_offset;
  3349.     if (replace_offset)
  3350.         vim_memmove(p + 1, p, (size_t)(replace_offset * sizeof(char_u)));
  3351.     *p = c;
  3352.     ++replace_stack_nr;
  3353. }
  3354.  
  3355. /*
  3356.  * pop one item from the replace stack
  3357.  * return -1 if stack empty
  3358.  * return 0 if no character was replaced
  3359.  * return replaced character otherwise
  3360.  */
  3361.     int
  3362. replace_pop()
  3363. {
  3364.     if (replace_stack_nr == 0)
  3365.         return -1;
  3366.     return (int)replace_stack[--replace_stack_nr];
  3367. }
  3368.  
  3369. /*
  3370.  * make the replace stack empty
  3371.  * (called when exiting replace mode)
  3372.  */
  3373.     void
  3374. replace_flush()
  3375. {
  3376.     vim_free(replace_stack);
  3377.     replace_stack = NULL;
  3378.     replace_stack_len = 0;
  3379.     replace_stack_nr = 0;
  3380. }
  3381.  
  3382. #if defined(LISPINDENT) || defined(CINDENT)
  3383. /*
  3384.  * Re-indent the current line, based on the current contents of it and the
  3385.  * surrounding lines. Fixing the cursor position seems really easy -- I'm very
  3386.  * confused what all the part that handles Control-T is doing that I'm not.
  3387.  * "get_the_indent" should be get_c_indent or get_lisp_indent.
  3388.  */
  3389.  
  3390.     void
  3391. fixthisline(get_the_indent)
  3392.     int (*get_the_indent) __ARGS((void));
  3393. {
  3394.     change_indent(INDENT_SET, get_the_indent(), FALSE);
  3395.     if (linewhite(curwin->w_cursor.lnum))
  3396.         did_ai = TRUE;        /* delete the indent if the line stays empty */
  3397. }
  3398. #endif /* defined(LISPINDENT) || defined(CINDENT) */
  3399.  
  3400. #ifdef CINDENT
  3401. /*
  3402.  * return TRUE if 'cinkeys' contains the key "keytyped",
  3403.  * when == '*':        Only if key is preceded with '*'    (indent before insert)
  3404.  * when == '!':        Only if key is prededed with '!'    (don't insert)
  3405.  * when == ' ':        Only if key is not preceded with '*'(indent afterwards)
  3406.  *
  3407.  * If line_is_empty is TRUE accept keys with '0' before them.
  3408.  */
  3409.     int
  3410. in_cinkeys(keytyped, when, line_is_empty)
  3411.     int            keytyped;
  3412.     int            when;
  3413.     int            line_is_empty;
  3414. {
  3415.     char_u    *look;
  3416.     int        try_match;
  3417.     char_u    *p;
  3418.  
  3419.     for (look = curbuf->b_p_cink; *look; )
  3420.     {
  3421.         /*
  3422.          * Find out if we want to try a match with this key, depending on
  3423.          * 'when' and a '*' or '!' before the key.
  3424.          */
  3425.         switch (when)
  3426.         {
  3427.             case '*': try_match = (*look == '*'); break;
  3428.             case '!': try_match = (*look == '!'); break;
  3429.              default: try_match = (*look != '*'); break;
  3430.         }
  3431.         if (*look == '*' || *look == '!')
  3432.             ++look;
  3433.  
  3434.         /*
  3435.          * If there is a '0', only accept a match if the line is empty.
  3436.          */
  3437.         if (*look == '0')
  3438.         {
  3439.             if (!line_is_empty)
  3440.                 try_match = FALSE;
  3441.             ++look;
  3442.         }
  3443.  
  3444.         /*
  3445.          * does it look like a control character?
  3446.          */
  3447.         if (*look == '^' && look[1] >= '@' && look[1] <= '_')
  3448.         {
  3449.             if (try_match && keytyped == Ctrl(look[1]))
  3450.                 return TRUE;
  3451.             look += 2;
  3452.         }
  3453.         /*
  3454.          * 'o' means "o" command, open forward.
  3455.          * 'O' means "O" command, open backward.
  3456.          */
  3457.         else if (*look == 'o')
  3458.         {
  3459.             if (try_match && keytyped == KEY_OPEN_FORW)
  3460.                 return TRUE;
  3461.             ++look;
  3462.         }
  3463.         else if (*look == 'O')
  3464.         {
  3465.             if (try_match && keytyped == KEY_OPEN_BACK)
  3466.                 return TRUE;
  3467.             ++look;
  3468.         }
  3469.  
  3470.         /*
  3471.          * 'e' means to check for "else" at start of line and just before the
  3472.          * cursor.
  3473.          */
  3474.         else if (*look == 'e')
  3475.         {
  3476.             if (try_match && keytyped == 'e' && curwin->w_cursor.col >= 4)
  3477.             {
  3478.                 p = ml_get_curline();
  3479.                 if (skipwhite(p) == p + curwin->w_cursor.col - 4 &&
  3480.                         STRNCMP(p + curwin->w_cursor.col - 4, "else", 4) == 0)
  3481.                     return TRUE;
  3482.             }
  3483.             ++look;
  3484.         }
  3485.  
  3486.         /*
  3487.          * ':' only causes an indent if it is at the end of a label or case
  3488.          * statement.
  3489.          */
  3490.         else if (*look == ':')
  3491.         {
  3492.             if (try_match && keytyped == ':')
  3493.             {
  3494.                 p = ml_get_curline();
  3495.                 if (iscase(p) || islabel(30))
  3496.                     return TRUE;
  3497.             }
  3498.             ++look;
  3499.         }
  3500.  
  3501.  
  3502.         /*
  3503.          * Is it a key in <>, maybe?
  3504.          */
  3505.         else if (*look == '<')
  3506.         {
  3507.             if (try_match)
  3508.             {
  3509.                 /*
  3510.                  * make up some named keys <o>, <O>, <e>, <0>, <>>, <<>, <*>
  3511.                  * and <!> so that people can re-indent on o, O, e, 0, <, >, *
  3512.                  * and ! keys if they really really want to.
  3513.                  */
  3514.                 if (vim_strchr((char_u *)"<>!*oOe0", look[1]) != NULL &&
  3515.                                                           keytyped == look[1])
  3516.                     return TRUE;
  3517.  
  3518.                 if (keytyped == get_special_key_code(look + 1))
  3519.                     return TRUE;
  3520.             }
  3521.             while (*look && *look != '>')
  3522.                 look++;
  3523.             while (*look == '>')
  3524.                 look++;
  3525.         }
  3526.  
  3527.         /*
  3528.          * ok, it's a boring generic character.
  3529.          */
  3530.         else
  3531.         {
  3532.             if (try_match && *look == keytyped)
  3533.                 return TRUE;
  3534.             ++look;
  3535.         }
  3536.  
  3537.         /*
  3538.          * Skip over ", ".
  3539.          */
  3540.         look = skip_to_option_part(look);
  3541.     }
  3542.     return FALSE;
  3543. }
  3544. #endif /* CINDENT */
  3545.  
  3546. #if defined(RIGHTLEFT) || defined(PROTO)
  3547. /*
  3548.  * Map Hebrew keyboard when in hkmap mode.
  3549.  */
  3550.     int
  3551. hkmap(c)
  3552.     int c;
  3553. {
  3554.     switch(c)
  3555.     {
  3556.         case '`':    return ';';
  3557.         case '/':    return '.';
  3558.         case '\'':    return ',';
  3559.         case 'q':    return '/';
  3560.         case 'w':    return '\'';
  3561.  
  3562.         /* Hebrew letters - set offset from 'a' */
  3563.         case ',':    c = '{'; break;
  3564.         case '.':    c = 'v'; break;
  3565.         case ';':    c = 't'; break;
  3566.         default: {
  3567.                     static char str[] = "zqbcxlsjphmkwonu ydafe rig";
  3568.  
  3569.                     if (c < 'a' || c > 'z')
  3570.                         return c;
  3571.                     c = str[c - 'a'];
  3572.                     break;
  3573.                 }
  3574.         }
  3575.  
  3576.     return c - 'a' + p_aleph;
  3577. }
  3578. #endif
  3579.